### Go Client-Server HTTP Signature Example Source: https://context7.com/go-fed/httpsig/llms.txt Demonstrates client-side request signing and server-side verification using RSA-SHA256. It includes key generation, request creation, signing, sending, and response verification. Dependencies include standard Go crypto libraries and the go-fed/httpsig library. ```go package main import ( "bytes" "crypto/rand" "crypto/rsa" "fmt" "io/ioutil" "net/http" "net/http/httptest" "time" "github.com/go-fed/httpsig" ) func main() { // Generate key pair privateKey, _ := rsa.GenerateKey(rand.Reader, 2048) publicKey := &privateKey.PublicKey // Setup server with verification server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Read body for digest verification body, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, "Cannot read body", http.StatusBadRequest) return } r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // Verify signature verifier, err := httpsig.NewVerifier(r) if err != nil { http.Error(w, "Invalid signature format: "+err.Error(), http.StatusUnauthorized) return } keyID := verifier.KeyId() if keyID != "my-client-key" { http.Error(w, "Unknown key ID", http.StatusUnauthorized) return } err = verifier.Verify(publicKey, httpsig.RSA_SHA256) if err != nil { http.Error(w, "Signature verification failed: "+err.Error(), http.StatusUnauthorized) return } // Success w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{"status":"authenticated","message":"Signature valid"}`) })) defer server.Close() // Client: Create and sign request signer, _, err := httpsig.NewSigner( []httpsig.Algorithm{httpsig.RSA_SHA256}, httpsig.DigestSha256, []string{httpsig.RequestTarget, "date", "digest"}, httpsig.Signature, 300, ) if err != nil { panic(err) } reqBody := []byte(`{"username":"alice","action":"login"}`) req, _ := http.NewRequest("POST", server.URL+"/api/authenticate", bytes.NewBuffer(reqBody)) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) req.Header.Set("Content-Type", "application/json") err = signer.SignRequest(privateKey, "my-client-key", req, reqBody) if err != nil { panic(err) } // Send signed request client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() respBody, _ := ioutil.ReadAll(resp.Body) fmt.Printf("Status: %d\n", resp.StatusCode) fmt.Printf("Response: %s\n", respBody) // Output: // Status: 200 // Response: {"status":"authenticated","message":"Signature valid"} } ``` -------------------------------- ### Sign and Verify HTTP Requests with ED25519 in Go Source: https://context7.com/go-fed/httpsig/llms.txt This Go code snippet demonstrates signing and verifying HTTP requests using ED25519 elliptic curve cryptography. It utilizes the go-fed/httpsig library and the golang.org/x/crypto/ed25519 package. The example includes generating an ED25519 key pair, creating a signer, signing a request with the private key, and then verifying it with the public key. ```go package main import ( "crypto/rand" "net/http" "time" "github.com/go-fed/httpsig" "golang.org/x/crypto/ed25519" ) func main() { // Generate ED25519 key pair publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) } // Create signer with ED25519 signer, algo, err := httpsig.NewSigner( []httpsig.Algorithm{httpsig.ED25519}, httpsig.DigestSha256, []string{"date", "digest", "(request-target)"}, httpsig.Signature, 3600, // 1 hour expiration ) if err != nil { panic(err) } // Create and sign request req, _ := http.NewRequest("POST", "https://api.example.com/submit", nil) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) bodyData := []byte(`{"action":"create","item":"document"}`) err = signer.SignRequest(privateKey, "ed25519-key-001", req, bodyData) if err != nil { panic(err) } // Verification verifier, err := httpsig.NewVerifier(req) if err != nil { panic(err) } err = verifier.Verify(publicKey, algo) if err != nil { panic(err) } // Successfully signed and verified with ED25519 // ED25519 provides faster signing/verification than RSA // with equivalent security at smaller key sizes } ``` -------------------------------- ### Verify HTTP Request Signatures with Go and httpsig Source: https://context7.com/go-fed/httpsig/llms.txt This Go code snippet demonstrates how to verify incoming signed HTTP requests using the `go-fed/httpsig` library. It involves setting up a KeyStore to manage public keys associated with key IDs and then using a Verifier to check the signature and digest of the request. This is crucial for ensuring the authenticity of requests received by a server. ```go package main import ( "crypto" "crypto/rsa" "crypto/x509" "encoding/pem" "io/ioutil" "net/http" "github.com/go-fed/httpsig" ) // KeyStore manages public keys by key ID type KeyStore struct { keys map[string]crypto.PublicKey algos map[string]httpsig.Algorithm } func NewKeyStore() *KeyStore { return &KeyStore{ keys: make(map[string]crypto.PublicKey), algos: make(map[string]httpsig.Algorithm), } } func (ks *KeyStore) AddKey(keyID string, pubKey crypto.PublicKey, algo httpsig.Algorithm) { ks.keys[keyID] = pubKey ks.algos[keyID] = algo } func (ks *KeyStore) VerifyRequest(r *http.Request) error { // Create verifier from request verifier, err := httpsig.NewVerifier(r) if err != nil { return err } // Get the key ID from the signature keyID := verifier.KeyId() // Lookup public key and algorithm pubKey, ok := ks.keys[keyID] if !ok { return httpsig.ErrKeyNotFound } algo, ok := ks.algos[keyID] if !ok { return httpsig.ErrAlgorithmNotFound } // Verify signature and digest err = verifier.Verify(pubKey, algo) if err != nil { return err } return nil } func main() { // Load public key from PEM file pemData, err := ioutil.ReadFile("client_public.pem") if err != nil { panic(err) } block, _ := pem.Decode(pemData) pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { panic(err) } rsaPubKey := pub.(*rsa.PublicKey) // Setup key store keyStore := NewKeyStore() keyStore.AddKey("client-key-001", rsaPubKey, httpsig.RSA_SHA256) // HTTP handler with verification http.HandleFunc("/api/secure", func(w http.ResponseWriter, r *http.Request) { err := keyStore.VerifyRequest(r) if err != nil { http.Error(w, "Signature verification failed: "+err.Error(), http.StatusUnauthorized) return } w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"verified"}`)) }) http.ListenAndServe(":8080", nil) } var ( ErrKeyNotFound = fmt.Errorf("public key not found for key ID") ErrAlgorithmNotFound = fmt.Errorf("algorithm not found for key ID") ) ``` -------------------------------- ### Sign HTTP Requests with SSH Keys using Go Source: https://context7.com/go-fed/httpsig/llms.txt Demonstrates how to sign HTTP requests using SSH private keys with the go-fed/httpsig library. This is useful for integrating with systems that use SSH-based authentication. It covers key generation, SSH signer creation, request signing, and verification. ```go package main import ( "crypto/rand" "io/ioutil" "net/http" "time" "github.com/go-fed/httpsig" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" ) func main() { // Generate ED25519 key for SSH _, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) } // Create SSH signer from ED25519 private key sshSigner, err := ssh.NewSignerFromKey(privateKey) if err != nil { panic(err) } // Create HTTP signature signer from SSH signer httpSigner, algo, err := httpsig.NewSSHSigner( sshSigner, httpsig.DigestSha256, []string{"date", "digest", "(request-target)"}, httpsig.Authorization, 1800, // 30 minute expiration ) if err != nil { panic(err) } // Create request req, _ := http.NewRequest("PUT", "https://api.example.com/update", nil) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) body := []byte(`{"update":"data"}`) // Sign request (note: no private key argument for SSH signer) err = httpSigner.SignRequest("ssh-key-fingerprint", req, body) if err != nil { panic(err) } // Load SSH public key from file for verification pubKeyData, _ := ioutil.ReadFile("id_ed25519.pub") sshPubKey, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyData) if err != nil { panic(err) } // Extract crypto.PublicKey from SSH public key cryptoPubKey := sshPubKey.(ssh.CryptoPublicKey).CryptoPublicKey() // Verify verifier, _ := httpsig.NewVerifier(req) err = verifier.Verify(cryptoPubKey, algo) if err != nil { panic(err) } // Successfully signed with SSH key and verified } ``` -------------------------------- ### Handle Concurrent Signing with httpsig Signer Source: https://github.com/go-fed/httpsig/blob/master/README.md Illustrates how to safely use the httpsig Signer in a concurrent environment, such as a web server handler. It shows the pattern of using a mutex to protect the Signer instance from simultaneous access by multiple goroutines. This ensures thread safety when signing HTTP responses. ```go import ( "net/http" "sync" "github.com/go-fed/httpsig" ) type server struct { signer httpsig.Signer mu *sync.Mutex } func (s *server) handlerFunc(w http.ResponseWriter, r *http.Request) { privateKey := ... // Obtain private key pubKeyId := ... // Obtain public key ID // Set headers and such on w s.mu.Lock() defer s.mu.Unlock() // To sign the digest, we need to give the signer a copy of the response body... // ...but it is optional, no digest will be signed if given "nil" body := ... // Obtain the response body here err := s.signer.SignResponse(privateKey, pubKeyId, w, body) if err != nil { // Handle error } // ... continue with writing response ... } ``` -------------------------------- ### Check Algorithm Support in Go for HTTP Signatures Source: https://context7.com/go-fed/httpsig/llms.txt This Go code snippet demonstrates how to check if specific signature and digest algorithms are supported by the go-fed/httpsig library. It iterates through lists of common algorithms and prints their support status, helping users ensure compatibility before implementation. ```go package main import ( "fmt" "github.com/go-fed/httpsig" ) func main() { // Check if signature algorithm is supported algorithms := []string{ "rsa-sha256", "rsa-sha512", "hmac-sha256", "ecdsa-sha256", "ed25519", "rsa-md5", // Not supported (cryptographically weak) } fmt.Println("Signature Algorithm Support:") for _, algo := range algorithms { supported := httpsig.IsSupportedHttpSigAlgorithm(algo) status := "✗ Not supported" if supported { status = "✓ Supported" } fmt.Printf(" %-20s %s\n", algo, status) } // Check digest algorithm support digestAlgos := []string{ "SHA-256", "SHA-512", "MD5", // Not supported (weak) } fmt.Println("\nDigest Algorithm Support:") for _, algo := range digestAlgos { supported := httpsig.IsSupportedDigestAlgorithm(algo) status := "✗ Not supported" if supported { status = "✓ Supported" } fmt.Printf(" %-20s %s\n", algo, status) } // Output: // Signature Algorithm Support: // rsa-sha256 ✓ Supported // rsa-sha512 ✓ Supported // hmac-sha256 ✓ Supported // ecdsa-sha256 ✓ Supported // ed25519 ✓ Supported // rsa-md5 ✗ Not supported // // Digest Algorithm Support: // SHA-256 ✓ Supported // SHA-512 ✓ Supported // MD5 ✗ Not supported } ``` -------------------------------- ### Sign and Verify HTTP Requests with HMAC in Go Source: https://context7.com/go-fed/httpsig/llms.txt This Go code snippet demonstrates how to sign and verify HTTP requests using HMAC algorithms with a shared secret key. It utilizes the go-fed/httpsig library and requires the crypto package. The process involves creating a signer, signing the request on the client side, and then verifying the signature on the server side using the same shared secret. ```go package main import ( "crypto" "crypto/rand" "net/http" "time" "github.com/go-fed/httpsig" ) func main() { // Generate shared secret key (store securely) sharedSecret := make([]byte, 64) _, err := rand.Read(sharedSecret) if err != nil { panic(err) } // CLIENT SIDE: Sign request with HMAC signer, _, err := httpsig.NewSigner( []httpsig.Algorithm{ httpsig.HMAC_SHA256, httpsig.HMAC_SHA512, }, httpsig.DigestSha256, []string{httpsig.RequestTarget, "date", "digest"}, httpsig.Authorization, 0, // No expiration ) if err != nil { panic(err) } req, _ := http.NewRequest("GET", "https://api.example.com/resource", nil) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) // Sign with shared secret (passed as crypto.PrivateKey) err = signer.SignRequest(crypto.PrivateKey(sharedSecret), "hmac-key-123", req, nil) if err != nil { panic(err) } // SERVER SIDE: Verify HMAC signature verifier, err := httpsig.NewVerifier(req) if err != nil { panic(err) } keyID := verifier.KeyId() // Returns "hmac-key-123" // Lookup shared secret for this key ID // In production, retrieve from secure key store // Verify with shared secret (passed as crypto.PublicKey) err = verifier.Verify(crypto.PublicKey(sharedSecret), httpsig.HMAC_SHA256) if err != nil { panic(err) } // Signature verified successfully } ``` -------------------------------- ### Sign HTTP Request with httpsig Source: https://github.com/go-fed/httpsig/blob/master/README.md Demonstrates how to sign an HTTP request using the httpsig package. It involves creating a Signer with specified algorithms and headers, and then calling SignRequest. The function requires a private key, public key ID, and the http.Request object. It optionally accepts the request body for Digest header signing. Note that Signer is not safe for concurrent use. ```go import ( "crypto" "net/http" "sync" "github.com/go-fed/httpsig" ) func sign(privateKey crypto.PrivateKey, pubKeyId string, r *http.Request) error { prefs := []httpsig.Algorithm{httpsig.RSA_SHA512, httpsig.RSA_SHA256} digestAlgorithm := DigestSha256 // Assuming DigestSha256 is defined elsewhere or using a constant from the package // The "Date" and "Digest" headers must already be set on r, as well as r.URL. headersToSign := []string{httpsig.RequestTarget, "date", "digest"} signer, chosenAlgo, err := httpsig.NewSigner(prefs, digestAlgorithm, headersToSign, httpsig.Signature) // Assuming httpsig.Signature is a constant for header type if err != nil { return err } // To sign the digest, we need to give the signer a copy of the body... // ...but it is optional, no digest will be signed if given "nil" body := ... // Obtain the request body here // If r were a http.ResponseWriter, call SignResponse instead. return signer.SignRequest(privateKey, pubKeyId, r, body) } ``` -------------------------------- ### Verify HTTP Request Signature with httpsig Source: https://github.com/go-fed/httpsig/blob/master/README.md Explains how to verify an HTTP request's signature using the httpsig Verifier. A Verifier is created from the incoming request, which provides the KeyId. The application must then retrieve the corresponding public key and algorithm to perform the verification. The Verifier automatically handles the verification of the Digest header along with the HTTP signature. ```go import ( "crypto" "net/http" "github.com/go-fed/httpsig" ) func verify(r *http.Request) error { verifier, err := httpsig.NewVerifier(r) if err != nil { return err } pubKeyId := verifier.KeyId() var algo httpsig.Algorithm = ... // Determine algorithm based on pubKeyId or other means var pubKey crypto.PublicKey = ... // Retrieve public key based on pubKeyId // The verifier will verify the Digest in addition to the HTTP signature return verifier.Verify(pubKey, algo) } ``` -------------------------------- ### Create HTTP Request Signer with RSA/HMAC in Go Source: https://context7.com/go-fed/httpsig/llms.txt Generates a `Signer` instance for signing HTTP requests using RSA or HMAC algorithms. It supports automatic Digest header generation per RFC 3230 and allows specifying headers to include in the signature. The signer can be configured with preferred algorithms, digest algorithms, headers, signature scheme, and expiration time. ```go package main import ( "crypto" "crypto/rand" "crypto/rsa" "net/http" "time" "github.com/go-fed/httpsig" ) func main() { // Generate RSA private key (in production, load from secure storage) privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } // Define algorithm preferences (first available will be used) algorithmPrefs := []httpsig.Algorithm{ httpsig.RSA_SHA512, httpsig.RSA_SHA256, } // Specify digest algorithm for body integrity digestAlgorithm := httpsig.DigestSha256 // Headers to include in signature headersToSign := []string{ httpsig.RequestTarget, // Include method and URI "date", "digest", "host", } // Create signer with 300 second expiration signer, chosenAlgo, err := httpsig.NewSigner( algorithmPrefs, digestAlgorithm, headersToSign, httpsig.Signature, // Use "Signature" header (or httpsig.Authorization) 300, // Expires in 300 seconds ) if err != nil { panic(err) } // Create HTTP request req, err := http.NewRequest("POST", "https://api.example.com/data", nil) if err != nil { panic(err) } // Set required headers req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) req.Host = "api.example.com" // Request body for digest calculation requestBody := []byte(`{"key":"value"}`) // Sign the request err = signer.SignRequest(privateKey, "key-id-001", req, requestBody) if err != nil { panic(err) } // Request now has Signature and Digest headers set // Output example: // Signature: keyId="key-id-001",algorithm="hs2019",created=1702684800, // expires=1702685100,headers="(request-target) date digest host", // signature="Base64EncodedSignature==" // Digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE= } ``` -------------------------------- ### Sign HTTP Responses with Go and httpsig Source: https://context7.com/go-fed/httpsig/llms.txt This Go code snippet shows how to sign HTTP responses from a server handler to ensure response integrity and authenticity. It uses the `go-fed/httpsig` library to generate a signature for the response body and includes it in the Authorization header. This process requires a private key and key ID for signing. ```go package main import ( "crypto" "crypto/rand" "crypto/rsa" "net/http" "sync" "time" "github.com/go-fed/httpsig" ) type SecureServer struct { signer httpsig.Signer privateKey crypto.PrivateKey keyID string mu sync.Mutex // Signers are not goroutine-safe } func NewSecureServer() (*SecureServer, error) { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, err } signer, _, err := httpsig.NewSigner( []httpsig.Algorithm{httpsig.RSA_SHA256}, httpsig.DigestSha512, []string{"date", "digest"}, httpsig.Authorization, // Use Authorization header 600, // 10 minute expiration ) if err != nil { return nil, err } return &SecureServer{ signer: signer, privateKey: privateKey, keyID: "server-key-2024", }, } func (s *SecureServer) Handler(w http.ResponseWriter, r *http.Request) { // Set response headers w.Header().Set("Date", time.Now().UTC().Format(http.TimeFormat)) w.Header().Set("Content-Type", "application/json") responseBody := []byte(`{"status":"success","data":{"id":123}}`) // Sign response (must be done before writing body) s.mu.Lock() err := s.signer.SignResponse(s.privateKey, s.keyID, w, responseBody) s.mu.Unlock() if err != nil { http.Error(w, "Signing failed", http.StatusInternalServerError) return } // Now write the response body w.WriteHeader(http.StatusOK) w.Write(responseBody) // Response includes: // Authorization: Signature keyId="server-key-2024",algorithm="hs2019", // headers="date digest",signature="Base64Signature==" // Digest: SHA-512=HashOfResponseBody== } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.