Documentation ¶
Overview ¶
Package gpgchallenge provides a Client and a Server so that a Client can prove ownership of an IP address by solving a GPG challenge sent by the Server at the claimed IP. The protocol is as follows:
- The Client GETs a random token from the server, at the /token endpoint, and signs that token with its GPG private key (armor detached signature).
- When it is ready[*], the client POSTs an application/x-www-form-urlencoded over HTTPS to the server, at the /claim endpoint. It sends the following URL-encoded values as the request body: its armor encoded public key as "pubkey", the IP address it's claiming as "challengeIP", the token it got from the server as "token", and the signature for the token as "signature".
- The Server receives the claim. It verifies that the token (nonce) is indeed one that it had generated. It parses the client's public key. It verifies with that public key that the sent signature matches the token. The serve ACKs to the client.
- The Server generates a random token, and POSTs it to the challenged IP (over HTTPS, with certificate verification disabled) at the /challenge endpoint.
- The Client receives the random token, signs it (armored detached signature), and sends the signature as a reply.
- The Server receives the signed token and verifies it with the Client's public key.
- At this point, the challenge is successful, so the Server performs the action registered through the OnSuccess function.
- The Server sends a last message to the Client at the /ack endpoint, depending on the result of the OnSuccess action. "ACK" if it was successful, the error message otherwise.
[*]As the Server connects to the Client to challenge it, the Client must obviously have a way, which does not need to be described by the protocol, to listen to and accept these connections.
Index ¶
Constants ¶
const SNISuffix = "-gpgchallenge"
SNISuffix is the Server Name Indication prefix used when dialing the client's handler. The SNI is challengeIP+SNISuffix.
Variables ¶
var ClientChallengedPort = 443
ClientChallengedPort is the port that the client will be challenged on by the server.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is used to prove ownership of an IP address, by answering a GPG challenge that the server sends at the address. A client must first register its Handler with an HTTPS server, before it can perform the challenge.
func NewClient ¶
NewClient returns a Client. keyRing and keyId are the GPG key ring and key ID used to fulfill the challenge. challengeIP is the address that client proves that it owns, by answering the challenge the server sends at this address.
func (*Client) Challenge ¶
Challenge requests a challenge from the server running at serverAddr, which should be a host name or of the hostname:port form, and then fulfills that challenge.
type Server ¶
type Server struct { // OnSuccess is user-defined, and it is run by the server upon // successuful verification of the client's challenge. Identity is the // short form of the client's public key's fingerprint in capital hex. // Address is the IP address that the client was claiming. OnSuccess func(identity, address string) error IPSeenMu sync.Mutex IPSeen map[string]time.Time // last time we saw a claimedIP, for rate-limiting purposes. // contains filtered or unexported fields }
Server sends a challenge when a client that wants to claim ownership of an IP address requests so. Server runs OnSuccess when the challenge is successful.
Directories ¶
Path | Synopsis |
---|---|
The client command is an example client of the gpgchallenge package.
|
The client command is an example client of the gpgchallenge package. |
The server command is an example server of the gpgchallenge package.
|
The server command is an example server of the gpgchallenge package. |