digest.go (2715B)
1 package httpsig 2 3 import ( 4 "bytes" 5 "crypto" 6 "encoding/base64" 7 "fmt" 8 "hash" 9 "net/http" 10 "strings" 11 ) 12 13 type DigestAlgorithm string 14 15 const ( 16 DigestSha256 DigestAlgorithm = "SHA-256" 17 DigestSha512 = "SHA-512" 18 ) 19 20 var digestToDef = map[DigestAlgorithm]crypto.Hash{ 21 DigestSha256: crypto.SHA256, 22 DigestSha512: crypto.SHA512, 23 } 24 25 // IsSupportedDigestAlgorithm returns true if hte string is supported by this 26 // library, is not a hash known to be weak, and is supported by the hardware. 27 func IsSupportedDigestAlgorithm(algo string) bool { 28 uc := DigestAlgorithm(strings.ToUpper(algo)) 29 c, ok := digestToDef[uc] 30 return ok && c.Available() 31 } 32 33 func getHash(alg DigestAlgorithm) (h hash.Hash, toUse DigestAlgorithm, err error) { 34 upper := DigestAlgorithm(strings.ToUpper(string(alg))) 35 c, ok := digestToDef[upper] 36 if !ok { 37 err = fmt.Errorf("unknown or unsupported Digest algorithm: %s", alg) 38 } else if !c.Available() { 39 err = fmt.Errorf("unavailable Digest algorithm: %s", alg) 40 } else { 41 h = c.New() 42 toUse = upper 43 } 44 return 45 } 46 47 const ( 48 digestHeader = "Digest" 49 digestDelim = "=" 50 ) 51 52 func addDigest(r *http.Request, algo DigestAlgorithm, b []byte) (err error) { 53 _, ok := r.Header[digestHeader] 54 if ok { 55 err = fmt.Errorf("cannot add Digest: Digest is already set") 56 return 57 } 58 var h hash.Hash 59 var a DigestAlgorithm 60 h, a, err = getHash(algo) 61 if err != nil { 62 return 63 } 64 h.Write(b) 65 sum := h.Sum(nil) 66 r.Header.Add(digestHeader, 67 fmt.Sprintf("%s%s%s", 68 a, 69 digestDelim, 70 base64.StdEncoding.EncodeToString(sum[:]))) 71 return 72 } 73 74 func addDigestResponse(r http.ResponseWriter, algo DigestAlgorithm, b []byte) (err error) { 75 _, ok := r.Header()[digestHeader] 76 if ok { 77 err = fmt.Errorf("cannot add Digest: Digest is already set") 78 return 79 } 80 var h hash.Hash 81 var a DigestAlgorithm 82 h, a, err = getHash(algo) 83 if err != nil { 84 return 85 } 86 h.Write(b) 87 sum := h.Sum(nil) 88 r.Header().Add(digestHeader, 89 fmt.Sprintf("%s%s%s", 90 a, 91 digestDelim, 92 base64.StdEncoding.EncodeToString(sum[:]))) 93 return 94 } 95 96 func verifyDigest(r *http.Request, body *bytes.Buffer) (err error) { 97 d := r.Header.Get(digestHeader) 98 if len(d) == 0 { 99 err = fmt.Errorf("cannot verify Digest: request has no Digest header") 100 return 101 } 102 elem := strings.SplitN(d, digestDelim, 2) 103 if len(elem) != 2 { 104 err = fmt.Errorf("cannot verify Digest: malformed Digest: %s", d) 105 return 106 } 107 var h hash.Hash 108 h, _, err = getHash(DigestAlgorithm(elem[0])) 109 if err != nil { 110 return 111 } 112 h.Write(body.Bytes()) 113 sum := h.Sum(nil) 114 encSum := base64.StdEncoding.EncodeToString(sum[:]) 115 if encSum != elem[1] { 116 err = fmt.Errorf("cannot verify Digest: header Digest does not match the digest of the request body") 117 return 118 } 119 return 120 }