gtsocial-umbx

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

algorithms.go (13984B)


      1 package httpsig
      2 
      3 import (
      4 	"crypto"
      5 	"crypto/ecdsa"
      6 	"crypto/hmac"
      7 	"crypto/rsa"
      8 	"crypto/sha1"
      9 	"crypto/sha256"
     10 	"crypto/sha512"
     11 	"crypto/subtle" // Use should trigger great care
     12 	"encoding/asn1"
     13 	"errors"
     14 	"fmt"
     15 	"hash"
     16 	"io"
     17 	"math/big"
     18 	"strings"
     19 
     20 	"golang.org/x/crypto/blake2b"
     21 	"golang.org/x/crypto/blake2s"
     22 	"golang.org/x/crypto/ed25519"
     23 	"golang.org/x/crypto/ripemd160"
     24 	"golang.org/x/crypto/sha3"
     25 	"golang.org/x/crypto/ssh"
     26 )
     27 
     28 const (
     29 	hmacPrefix        = "hmac"
     30 	rsaPrefix         = "rsa"
     31 	sshPrefix         = "ssh"
     32 	ecdsaPrefix       = "ecdsa"
     33 	ed25519Prefix     = "ed25519"
     34 	md4String         = "md4"
     35 	md5String         = "md5"
     36 	sha1String        = "sha1"
     37 	sha224String      = "sha224"
     38 	sha256String      = "sha256"
     39 	sha384String      = "sha384"
     40 	sha512String      = "sha512"
     41 	md5sha1String     = "md5sha1"
     42 	ripemd160String   = "ripemd160"
     43 	sha3_224String    = "sha3-224"
     44 	sha3_256String    = "sha3-256"
     45 	sha3_384String    = "sha3-384"
     46 	sha3_512String    = "sha3-512"
     47 	sha512_224String  = "sha512-224"
     48 	sha512_256String  = "sha512-256"
     49 	blake2s_256String = "blake2s-256"
     50 	blake2b_256String = "blake2b-256"
     51 	blake2b_384String = "blake2b-384"
     52 	blake2b_512String = "blake2b-512"
     53 )
     54 
     55 var blake2Algorithms = map[crypto.Hash]bool{
     56 	crypto.BLAKE2s_256: true,
     57 	crypto.BLAKE2b_256: true,
     58 	crypto.BLAKE2b_384: true,
     59 	crypto.BLAKE2b_512: true,
     60 }
     61 
     62 var hashToDef = map[crypto.Hash]struct {
     63 	name string
     64 	new  func(key []byte) (hash.Hash, error) // Only MACers will accept a key
     65 }{
     66 	// Which standard names these?
     67 	// The spec lists the following as a canonical reference, which is dead:
     68 	// http://www.iana.org/assignments/signature-algorithms
     69 	//
     70 	// Note that the forbidden hashes have an invalid 'new' function.
     71 	crypto.MD4: {md4String, func(key []byte) (hash.Hash, error) { return nil, nil }},
     72 	crypto.MD5: {md5String, func(key []byte) (hash.Hash, error) { return nil, nil }},
     73 	// Temporarily enable SHA1 because of issue https://github.com/golang/go/issues/37278
     74 	crypto.SHA1:        {sha1String, func(key []byte) (hash.Hash, error) { return sha1.New(), nil }},
     75 	crypto.SHA224:      {sha224String, func(key []byte) (hash.Hash, error) { return sha256.New224(), nil }},
     76 	crypto.SHA256:      {sha256String, func(key []byte) (hash.Hash, error) { return sha256.New(), nil }},
     77 	crypto.SHA384:      {sha384String, func(key []byte) (hash.Hash, error) { return sha512.New384(), nil }},
     78 	crypto.SHA512:      {sha512String, func(key []byte) (hash.Hash, error) { return sha512.New(), nil }},
     79 	crypto.MD5SHA1:     {md5sha1String, func(key []byte) (hash.Hash, error) { return nil, nil }},
     80 	crypto.RIPEMD160:   {ripemd160String, func(key []byte) (hash.Hash, error) { return ripemd160.New(), nil }},
     81 	crypto.SHA3_224:    {sha3_224String, func(key []byte) (hash.Hash, error) { return sha3.New224(), nil }},
     82 	crypto.SHA3_256:    {sha3_256String, func(key []byte) (hash.Hash, error) { return sha3.New256(), nil }},
     83 	crypto.SHA3_384:    {sha3_384String, func(key []byte) (hash.Hash, error) { return sha3.New384(), nil }},
     84 	crypto.SHA3_512:    {sha3_512String, func(key []byte) (hash.Hash, error) { return sha3.New512(), nil }},
     85 	crypto.SHA512_224:  {sha512_224String, func(key []byte) (hash.Hash, error) { return sha512.New512_224(), nil }},
     86 	crypto.SHA512_256:  {sha512_256String, func(key []byte) (hash.Hash, error) { return sha512.New512_256(), nil }},
     87 	crypto.BLAKE2s_256: {blake2s_256String, func(key []byte) (hash.Hash, error) { return blake2s.New256(key) }},
     88 	crypto.BLAKE2b_256: {blake2b_256String, func(key []byte) (hash.Hash, error) { return blake2b.New256(key) }},
     89 	crypto.BLAKE2b_384: {blake2b_384String, func(key []byte) (hash.Hash, error) { return blake2b.New384(key) }},
     90 	crypto.BLAKE2b_512: {blake2b_512String, func(key []byte) (hash.Hash, error) { return blake2b.New512(key) }},
     91 }
     92 
     93 var stringToHash map[string]crypto.Hash
     94 
     95 const (
     96 	defaultAlgorithm        = RSA_SHA256
     97 	defaultAlgorithmHashing = sha256String
     98 )
     99 
    100 func init() {
    101 	stringToHash = make(map[string]crypto.Hash, len(hashToDef))
    102 	for k, v := range hashToDef {
    103 		stringToHash[v.name] = k
    104 	}
    105 	// This should guarantee that at runtime the defaultAlgorithm will not
    106 	// result in errors when fetching a macer or signer (see algorithms.go)
    107 	if ok, err := isAvailable(string(defaultAlgorithmHashing)); err != nil {
    108 		panic(err)
    109 	} else if !ok {
    110 		panic(fmt.Sprintf("the default httpsig algorithm is unavailable: %q", defaultAlgorithm))
    111 	}
    112 }
    113 
    114 func isForbiddenHash(h crypto.Hash) bool {
    115 	switch h {
    116 	// Not actually cryptographically secure
    117 	case crypto.MD4:
    118 		fallthrough
    119 	case crypto.MD5:
    120 		fallthrough
    121 	case crypto.MD5SHA1: // shorthand for crypto/tls, not actually implemented
    122 		return true
    123 	}
    124 	// Still cryptographically secure
    125 	return false
    126 }
    127 
    128 // signer is an internally public type.
    129 type signer interface {
    130 	Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error)
    131 	Verify(pub crypto.PublicKey, toHash, signature []byte) error
    132 	String() string
    133 }
    134 
    135 // macer is an internally public type.
    136 type macer interface {
    137 	Sign(sig, key []byte) ([]byte, error)
    138 	Equal(sig, actualMAC, key []byte) (bool, error)
    139 	String() string
    140 }
    141 
    142 var _ macer = &hmacAlgorithm{}
    143 
    144 type hmacAlgorithm struct {
    145 	fn   func(key []byte) (hash.Hash, error)
    146 	kind crypto.Hash
    147 }
    148 
    149 func (h *hmacAlgorithm) Sign(sig, key []byte) ([]byte, error) {
    150 	hs, err := h.fn(key)
    151 	if err = setSig(hs, sig); err != nil {
    152 		return nil, err
    153 	}
    154 	return hs.Sum(nil), nil
    155 }
    156 
    157 func (h *hmacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) {
    158 	hs, err := h.fn(key)
    159 	if err != nil {
    160 		return false, err
    161 	}
    162 	defer hs.Reset()
    163 	err = setSig(hs, sig)
    164 	if err != nil {
    165 		return false, err
    166 	}
    167 	expected := hs.Sum(nil)
    168 	return hmac.Equal(actualMAC, expected), nil
    169 }
    170 
    171 func (h *hmacAlgorithm) String() string {
    172 	return fmt.Sprintf("%s-%s", hmacPrefix, hashToDef[h.kind].name)
    173 }
    174 
    175 var _ signer = &rsaAlgorithm{}
    176 
    177 type rsaAlgorithm struct {
    178 	hash.Hash
    179 	kind      crypto.Hash
    180 	sshSigner ssh.Signer
    181 }
    182 
    183 func (r *rsaAlgorithm) setSig(b []byte) error {
    184 	n, err := r.Write(b)
    185 	if err != nil {
    186 		r.Reset()
    187 		return err
    188 	} else if n != len(b) {
    189 		r.Reset()
    190 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b))
    191 	}
    192 	return nil
    193 }
    194 
    195 func (r *rsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) {
    196 	if r.sshSigner != nil {
    197 		sshsig, err := r.sshSigner.Sign(rand, sig)
    198 		if err != nil {
    199 			return nil, err
    200 		}
    201 
    202 		return sshsig.Blob, nil
    203 	}
    204 	defer r.Reset()
    205 
    206 	if err := r.setSig(sig); err != nil {
    207 		return nil, err
    208 	}
    209 	rsaK, ok := p.(*rsa.PrivateKey)
    210 	if !ok {
    211 		return nil, errors.New("crypto.PrivateKey is not *rsa.PrivateKey")
    212 	}
    213 	return rsa.SignPKCS1v15(rand, rsaK, r.kind, r.Sum(nil))
    214 }
    215 
    216 func (r *rsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error {
    217 	defer r.Reset()
    218 	rsaK, ok := pub.(*rsa.PublicKey)
    219 	if !ok {
    220 		return errors.New("crypto.PublicKey is not *rsa.PublicKey")
    221 	}
    222 	if err := r.setSig(toHash); err != nil {
    223 		return err
    224 	}
    225 	return rsa.VerifyPKCS1v15(rsaK, r.kind, r.Sum(nil), signature)
    226 }
    227 
    228 func (r *rsaAlgorithm) String() string {
    229 	return fmt.Sprintf("%s-%s", rsaPrefix, hashToDef[r.kind].name)
    230 }
    231 
    232 var _ signer = &ed25519Algorithm{}
    233 
    234 type ed25519Algorithm struct {
    235 	sshSigner ssh.Signer
    236 }
    237 
    238 func (r *ed25519Algorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) {
    239 	if r.sshSigner != nil {
    240 		sshsig, err := r.sshSigner.Sign(rand, sig)
    241 		if err != nil {
    242 			return nil, err
    243 		}
    244 
    245 		return sshsig.Blob, nil
    246 	}
    247 	ed25519K, ok := p.(ed25519.PrivateKey)
    248 	if !ok {
    249 		return nil, errors.New("crypto.PrivateKey is not ed25519.PrivateKey")
    250 	}
    251 	return ed25519.Sign(ed25519K, sig), nil
    252 }
    253 
    254 func (r *ed25519Algorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error {
    255 	ed25519K, ok := pub.(ed25519.PublicKey)
    256 	if !ok {
    257 		return errors.New("crypto.PublicKey is not ed25519.PublicKey")
    258 	}
    259 
    260 	if ed25519.Verify(ed25519K, toHash, signature) {
    261 		return nil
    262 	}
    263 
    264 	return errors.New("ed25519 verify failed")
    265 }
    266 
    267 func (r *ed25519Algorithm) String() string {
    268 	return fmt.Sprintf("%s", ed25519Prefix)
    269 }
    270 
    271 var _ signer = &ecdsaAlgorithm{}
    272 
    273 type ecdsaAlgorithm struct {
    274 	hash.Hash
    275 	kind crypto.Hash
    276 }
    277 
    278 func (r *ecdsaAlgorithm) setSig(b []byte) error {
    279 	n, err := r.Write(b)
    280 	if err != nil {
    281 		r.Reset()
    282 		return err
    283 	} else if n != len(b) {
    284 		r.Reset()
    285 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b))
    286 	}
    287 	return nil
    288 }
    289 
    290 type ECDSASignature struct {
    291 	R, S *big.Int
    292 }
    293 
    294 func (r *ecdsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) {
    295 	defer r.Reset()
    296 	if err := r.setSig(sig); err != nil {
    297 		return nil, err
    298 	}
    299 	ecdsaK, ok := p.(*ecdsa.PrivateKey)
    300 	if !ok {
    301 		return nil, errors.New("crypto.PrivateKey is not *ecdsa.PrivateKey")
    302 	}
    303 	R, S, err := ecdsa.Sign(rand, ecdsaK, r.Sum(nil))
    304 	if err != nil {
    305 		return nil, err
    306 	}
    307 
    308 	signature := ECDSASignature{R: R, S: S}
    309 	bytes, err := asn1.Marshal(signature)
    310 
    311 	return bytes, err
    312 }
    313 
    314 func (r *ecdsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error {
    315 	defer r.Reset()
    316 	ecdsaK, ok := pub.(*ecdsa.PublicKey)
    317 	if !ok {
    318 		return errors.New("crypto.PublicKey is not *ecdsa.PublicKey")
    319 	}
    320 	if err := r.setSig(toHash); err != nil {
    321 		return err
    322 	}
    323 
    324 	sig := new(ECDSASignature)
    325 	_, err := asn1.Unmarshal(signature, sig)
    326 	if err != nil {
    327 		return err
    328 	}
    329 
    330 	if ecdsa.Verify(ecdsaK, r.Sum(nil), sig.R, sig.S) {
    331 		return nil
    332 	} else {
    333 		return errors.New("Invalid signature")
    334 	}
    335 }
    336 
    337 func (r *ecdsaAlgorithm) String() string {
    338 	return fmt.Sprintf("%s-%s", ecdsaPrefix, hashToDef[r.kind].name)
    339 }
    340 
    341 var _ macer = &blakeMacAlgorithm{}
    342 
    343 type blakeMacAlgorithm struct {
    344 	fn   func(key []byte) (hash.Hash, error)
    345 	kind crypto.Hash
    346 }
    347 
    348 func (r *blakeMacAlgorithm) Sign(sig, key []byte) ([]byte, error) {
    349 	hs, err := r.fn(key)
    350 	if err != nil {
    351 		return nil, err
    352 	}
    353 	if err = setSig(hs, sig); err != nil {
    354 		return nil, err
    355 	}
    356 	return hs.Sum(nil), nil
    357 }
    358 
    359 func (r *blakeMacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) {
    360 	hs, err := r.fn(key)
    361 	if err != nil {
    362 		return false, err
    363 	}
    364 	defer hs.Reset()
    365 	err = setSig(hs, sig)
    366 	if err != nil {
    367 		return false, err
    368 	}
    369 	expected := hs.Sum(nil)
    370 	return subtle.ConstantTimeCompare(actualMAC, expected) == 1, nil
    371 }
    372 
    373 func (r *blakeMacAlgorithm) String() string {
    374 	return fmt.Sprintf("%s", hashToDef[r.kind].name)
    375 }
    376 
    377 func setSig(a hash.Hash, b []byte) error {
    378 	n, err := a.Write(b)
    379 	if err != nil {
    380 		a.Reset()
    381 		return err
    382 	} else if n != len(b) {
    383 		a.Reset()
    384 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b))
    385 	}
    386 	return nil
    387 }
    388 
    389 // IsSupportedHttpSigAlgorithm returns true if the string is supported by this
    390 // library, is not a hash known to be weak, and is supported by the hardware.
    391 func IsSupportedHttpSigAlgorithm(algo string) bool {
    392 	a, err := isAvailable(algo)
    393 	return a && err == nil
    394 }
    395 
    396 // isAvailable is an internally public function
    397 func isAvailable(algo string) (bool, error) {
    398 	c, ok := stringToHash[algo]
    399 	if !ok {
    400 		return false, fmt.Errorf("no match for %q", algo)
    401 	}
    402 	if isForbiddenHash(c) {
    403 		return false, fmt.Errorf("forbidden hash type in %q", algo)
    404 	}
    405 	return c.Available(), nil
    406 }
    407 
    408 func newAlgorithmConstructor(algo string) (fn func(k []byte) (hash.Hash, error), c crypto.Hash, e error) {
    409 	ok := false
    410 	c, ok = stringToHash[algo]
    411 	if !ok {
    412 		e = fmt.Errorf("no match for %q", algo)
    413 		return
    414 	}
    415 	if isForbiddenHash(c) {
    416 		e = fmt.Errorf("forbidden hash type in %q", algo)
    417 		return
    418 	}
    419 	algoDef, ok := hashToDef[c]
    420 	if !ok {
    421 		e = fmt.Errorf("have crypto.Hash %v but no definition", c)
    422 		return
    423 	}
    424 	fn = func(key []byte) (hash.Hash, error) {
    425 		h, err := algoDef.new(key)
    426 		if err != nil {
    427 			return nil, err
    428 		}
    429 		return h, nil
    430 	}
    431 	return
    432 }
    433 
    434 func newAlgorithm(algo string, key []byte) (hash.Hash, crypto.Hash, error) {
    435 	fn, c, err := newAlgorithmConstructor(algo)
    436 	if err != nil {
    437 		return nil, c, err
    438 	}
    439 	h, err := fn(key)
    440 	return h, c, err
    441 }
    442 
    443 func signerFromSSHSigner(sshSigner ssh.Signer, s string) (signer, error) {
    444 	switch {
    445 	case strings.HasPrefix(s, rsaPrefix):
    446 		return &rsaAlgorithm{
    447 			sshSigner: sshSigner,
    448 		}, nil
    449 	case strings.HasPrefix(s, ed25519Prefix):
    450 		return &ed25519Algorithm{
    451 			sshSigner: sshSigner,
    452 		}, nil
    453 	default:
    454 		return nil, fmt.Errorf("no signer matching %q", s)
    455 	}
    456 }
    457 
    458 // signerFromString is an internally public method constructor
    459 func signerFromString(s string) (signer, error) {
    460 	s = strings.ToLower(s)
    461 	isEcdsa := false
    462 	isEd25519 := false
    463 	var algo string = ""
    464 	if strings.HasPrefix(s, ecdsaPrefix) {
    465 		algo = strings.TrimPrefix(s, ecdsaPrefix+"-")
    466 		isEcdsa = true
    467 	} else if strings.HasPrefix(s, rsaPrefix) {
    468 		algo = strings.TrimPrefix(s, rsaPrefix+"-")
    469 	} else if strings.HasPrefix(s, ed25519Prefix) {
    470 		isEd25519 = true
    471 		algo = "sha512"
    472 	} else {
    473 		return nil, fmt.Errorf("no signer matching %q", s)
    474 	}
    475 	hash, cHash, err := newAlgorithm(algo, nil)
    476 	if err != nil {
    477 		return nil, err
    478 	}
    479 	if isEd25519 {
    480 		return &ed25519Algorithm{}, nil
    481 	}
    482 	if isEcdsa {
    483 		return &ecdsaAlgorithm{
    484 			Hash: hash,
    485 			kind: cHash,
    486 		}, nil
    487 	}
    488 	return &rsaAlgorithm{
    489 		Hash: hash,
    490 		kind: cHash,
    491 	}, nil
    492 }
    493 
    494 // macerFromString is an internally public method constructor
    495 func macerFromString(s string) (macer, error) {
    496 	s = strings.ToLower(s)
    497 	if strings.HasPrefix(s, hmacPrefix) {
    498 		algo := strings.TrimPrefix(s, hmacPrefix+"-")
    499 		hashFn, cHash, err := newAlgorithmConstructor(algo)
    500 		if err != nil {
    501 			return nil, err
    502 		}
    503 		// Ensure below does not panic
    504 		_, err = hashFn(nil)
    505 		if err != nil {
    506 			return nil, err
    507 		}
    508 		return &hmacAlgorithm{
    509 			fn: func(key []byte) (hash.Hash, error) {
    510 				return hmac.New(func() hash.Hash {
    511 					h, e := hashFn(nil)
    512 					if e != nil {
    513 						panic(e)
    514 					}
    515 					return h
    516 				}, key), nil
    517 			},
    518 			kind: cHash,
    519 		}, nil
    520 	} else if bl, ok := stringToHash[s]; ok && blake2Algorithms[bl] {
    521 		hashFn, cHash, err := newAlgorithmConstructor(s)
    522 		if err != nil {
    523 			return nil, err
    524 		}
    525 		return &blakeMacAlgorithm{
    526 			fn:   hashFn,
    527 			kind: cHash,
    528 		}, nil
    529 	} else {
    530 		return nil, fmt.Errorf("no MACer matching %q", s)
    531 	}
    532 }