Verify verifies signature of the request.
(req *http.Request, keyFn func(keyID string) (crypto.PublicKey, error))
| 14 | |
| 15 | // Verify verifies signature of the request. |
| 16 | func Verify(req *http.Request, keyFn func(keyID string) (crypto.PublicKey, error)) error { |
| 17 | sigHeader := req.Header.Get("Signature") |
| 18 | if sigHeader == "" { |
| 19 | return errors.New("signature header is missing") |
| 20 | } |
| 21 | |
| 22 | var ( |
| 23 | pubKey crypto.PublicKey |
| 24 | algo string |
| 25 | sig []byte |
| 26 | headers []string |
| 27 | err error |
| 28 | ) |
| 29 | for _, part := range strings.Split(sigHeader, ",") { |
| 30 | k, v := strings.SplitN(part, "=", 2)[0], strings.SplitN(part, "=", 2)[1] |
| 31 | switch k { |
| 32 | case "keyId": |
| 33 | keyID := strings.Trim(v, "\"") |
| 34 | pubKey, err = keyFn(keyID) |
| 35 | if err != nil { |
| 36 | return err |
| 37 | } |
| 38 | case "algorithm": |
| 39 | algo = strings.Trim(v, "\"") |
| 40 | case "headers": |
| 41 | headers = strings.Split(strings.Trim(v, "\""), " ") |
| 42 | case "signature": |
| 43 | sig, err = base64.StdEncoding.DecodeString(strings.Trim(v, "\"")) |
| 44 | if err != nil { |
| 45 | return err |
| 46 | } |
| 47 | default: |
| 48 | return fmt.Errorf("unknown signature part: %s", part) |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | var sb strings.Builder |
| 53 | for _, header := range headers { |
| 54 | switch header { |
| 55 | case RequestTarget: |
| 56 | sb.WriteString("(request-target): ") |
| 57 | sb.WriteString(strings.ToLower(req.Method)) |
| 58 | sb.WriteString(" ") |
| 59 | sb.WriteString(req.URL.Path) |
| 60 | |
| 61 | if req.URL.RawQuery != "" { |
| 62 | sb.WriteString("?") |
| 63 | sb.WriteString(req.URL.RawQuery) |
| 64 | } |
| 65 | case "Host", "host": |
| 66 | sb.WriteString("host: ") |
| 67 | sb.WriteString(req.Host) |
| 68 | case "Date", "date": |
| 69 | sb.WriteString("date: ") |
| 70 | sb.WriteString(req.Header.Get("Date")) |
| 71 | case "Accept", "accept": |
| 72 | sb.WriteString("accept: ") |
| 73 | sb.WriteString(req.Header.Get("Accept")) |