gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }