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 }