Blame


1 71191436 2024-02-28 o package apub
2 71191436 2024-02-28 o
3 71191436 2024-02-28 o import (
4 71191436 2024-02-28 o "bytes"
5 71191436 2024-02-28 o "crypto"
6 71191436 2024-02-28 o "crypto/rand"
7 71191436 2024-02-28 o "crypto/rsa"
8 71191436 2024-02-28 o "crypto/sha256"
9 71191436 2024-02-28 o "encoding/base64"
10 71191436 2024-02-28 o "fmt"
11 71191436 2024-02-28 o "io"
12 71191436 2024-02-28 o "net/http"
13 71191436 2024-02-28 o "strings"
14 71191436 2024-02-28 o "time"
15 71191436 2024-02-28 o )
16 71191436 2024-02-28 o
17 71191436 2024-02-28 o // Sign signs the given HTTP request with the matching private key of the
18 71191436 2024-02-28 o // public key available at pubkeyURL.
19 71191436 2024-02-28 o func Sign(req *http.Request, key *rsa.PrivateKey, pubkeyURL string) error {
20 b526632b 2024-03-16 o if pubkeyURL == "" {
21 b526632b 2024-03-16 o return fmt.Errorf("no pubkey url")
22 b526632b 2024-03-16 o }
23 71191436 2024-02-28 o date := time.Now().UTC().Format(http.TimeFormat)
24 71191436 2024-02-28 o req.Header.Set("Date", date)
25 71191436 2024-02-28 o hash := sha256.New()
26 ed0db64a 2024-03-18 o toSign := []string{"(request-target)", "host", "date"}
27 71191436 2024-02-28 o fmt.Fprintln(hash, "(request-target):", strings.ToLower(req.Method), req.URL.Path)
28 71191436 2024-02-28 o fmt.Fprintln(hash, "host:", req.URL.Hostname())
29 ed0db64a 2024-03-18 o fmt.Fprintf(hash, "date: %s", date)
30 71191436 2024-02-28 o
31 ed0db64a 2024-03-18 o if req.Body != nil {
32 ed0db64a 2024-03-18 o // we're adding one more entry to our signature, so one more line.
33 ed0db64a 2024-03-18 o fmt.Fprint(hash, "\n")
34 ed0db64a 2024-03-18 o buf := &bytes.Buffer{}
35 ed0db64a 2024-03-18 o io.Copy(buf, req.Body)
36 ed0db64a 2024-03-18 o req.Body.Close()
37 ed0db64a 2024-03-18 o req.Body = io.NopCloser(buf)
38 ed0db64a 2024-03-18 o digest := sha256.Sum256(buf.Bytes())
39 ed0db64a 2024-03-18 o d := "SHA-256=" + base64.StdEncoding.EncodeToString(digest[:])
40 ed0db64a 2024-03-18 o toSign = append(toSign, "digest")
41 ed0db64a 2024-03-18 o fmt.Fprintf(hash, "digest: %s", d)
42 ed0db64a 2024-03-18 o req.Header.Set("Digest", d)
43 ed0db64a 2024-03-18 o }
44 71191436 2024-02-28 o sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash.Sum(nil))
45 71191436 2024-02-28 o if err != nil {
46 71191436 2024-02-28 o return err
47 71191436 2024-02-28 o }
48 71191436 2024-02-28 o bsig := base64.StdEncoding.EncodeToString(sig)
49 71191436 2024-02-28 o
50 ed0db64a 2024-03-18 o val := fmt.Sprintf("keyId=%q,algorithm=%q,headers=%q,signature=%q", pubkeyURL, "rsa-sha256", strings.Join(toSign, " "), bsig)
51 71191436 2024-02-28 o req.Header.Set("Signature", val)
52 71191436 2024-02-28 o return nil
53 71191436 2024-02-28 o }
54 71191436 2024-02-28 o
55 71191436 2024-02-28 o type signature struct {
56 71191436 2024-02-28 o keyID string
57 71191436 2024-02-28 o algorithm string
58 71191436 2024-02-28 o headers string
59 71191436 2024-02-28 o signature string
60 71191436 2024-02-28 o }
61 71191436 2024-02-28 o
62 71191436 2024-02-28 o func parseSignatureHeader(line string) (signature, error) {
63 71191436 2024-02-28 o var sig signature
64 71191436 2024-02-28 o for _, v := range strings.Split(line, ",") {
65 71191436 2024-02-28 o name, val, ok := strings.Cut(v, "=")
66 71191436 2024-02-28 o if !ok {
67 71191436 2024-02-28 o return sig, fmt.Errorf("bad field: %s from %s", v, line)
68 71191436 2024-02-28 o }
69 71191436 2024-02-28 o val = strings.Trim(val, `"`)
70 71191436 2024-02-28 o switch name {
71 71191436 2024-02-28 o case "keyId":
72 71191436 2024-02-28 o sig.keyID = val
73 71191436 2024-02-28 o case "algorithm":
74 71191436 2024-02-28 o sig.algorithm = val
75 71191436 2024-02-28 o case "headers":
76 71191436 2024-02-28 o sig.headers = val
77 71191436 2024-02-28 o case "signature":
78 71191436 2024-02-28 o sig.signature = val
79 71191436 2024-02-28 o default:
80 71191436 2024-02-28 o return signature{}, fmt.Errorf("bad field name %s", name)
81 71191436 2024-02-28 o }
82 71191436 2024-02-28 o }
83 71191436 2024-02-28 o
84 71191436 2024-02-28 o if sig.keyID == "" {
85 71191436 2024-02-28 o return sig, fmt.Errorf("missing signature field keyId")
86 71191436 2024-02-28 o } else if sig.algorithm == "" {
87 71191436 2024-02-28 o return sig, fmt.Errorf("missing signature field algorithm")
88 71191436 2024-02-28 o } else if sig.headers == "" {
89 71191436 2024-02-28 o return sig, fmt.Errorf("missing signature field headers")
90 71191436 2024-02-28 o } else if sig.signature == "" {
91 71191436 2024-02-28 o return sig, fmt.Errorf("missing signature field signature")
92 71191436 2024-02-28 o }
93 71191436 2024-02-28 o return sig, nil
94 71191436 2024-02-28 o }