| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- package mint
- import (
- "bytes"
- "crypto"
- "crypto/aes"
- "crypto/cipher"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/hmac"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/asn1"
- "fmt"
- "math/big"
- "time"
- "golang.org/x/crypto/curve25519"
- // Blank includes to ensure hash support
- _ "crypto/sha1"
- _ "crypto/sha256"
- _ "crypto/sha512"
- )
- var prng = rand.Reader
- type aeadFactory func(key []byte) (cipher.AEAD, error)
- type CipherSuiteParams struct {
- Suite CipherSuite
- Cipher aeadFactory // Cipher factory
- Hash crypto.Hash // Hash function
- KeyLen int // Key length in octets
- IvLen int // IV length in octets
- }
- type signatureAlgorithm uint8
- const (
- signatureAlgorithmUnknown = iota
- signatureAlgorithmRSA_PKCS1
- signatureAlgorithmRSA_PSS
- signatureAlgorithmECDSA
- )
- var (
- hashMap = map[SignatureScheme]crypto.Hash{
- RSA_PKCS1_SHA1: crypto.SHA1,
- RSA_PKCS1_SHA256: crypto.SHA256,
- RSA_PKCS1_SHA384: crypto.SHA384,
- RSA_PKCS1_SHA512: crypto.SHA512,
- ECDSA_P256_SHA256: crypto.SHA256,
- ECDSA_P384_SHA384: crypto.SHA384,
- ECDSA_P521_SHA512: crypto.SHA512,
- RSA_PSS_SHA256: crypto.SHA256,
- RSA_PSS_SHA384: crypto.SHA384,
- RSA_PSS_SHA512: crypto.SHA512,
- }
- sigMap = map[SignatureScheme]signatureAlgorithm{
- RSA_PKCS1_SHA1: signatureAlgorithmRSA_PKCS1,
- RSA_PKCS1_SHA256: signatureAlgorithmRSA_PKCS1,
- RSA_PKCS1_SHA384: signatureAlgorithmRSA_PKCS1,
- RSA_PKCS1_SHA512: signatureAlgorithmRSA_PKCS1,
- ECDSA_P256_SHA256: signatureAlgorithmECDSA,
- ECDSA_P384_SHA384: signatureAlgorithmECDSA,
- ECDSA_P521_SHA512: signatureAlgorithmECDSA,
- RSA_PSS_SHA256: signatureAlgorithmRSA_PSS,
- RSA_PSS_SHA384: signatureAlgorithmRSA_PSS,
- RSA_PSS_SHA512: signatureAlgorithmRSA_PSS,
- }
- curveMap = map[SignatureScheme]NamedGroup{
- ECDSA_P256_SHA256: P256,
- ECDSA_P384_SHA384: P384,
- ECDSA_P521_SHA512: P521,
- }
- newAESGCM = func(key []byte) (cipher.AEAD, error) {
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- // TLS always uses 12-byte nonces
- return cipher.NewGCMWithNonceSize(block, 12)
- }
- cipherSuiteMap = map[CipherSuite]CipherSuiteParams{
- TLS_AES_128_GCM_SHA256: {
- Suite: TLS_AES_128_GCM_SHA256,
- Cipher: newAESGCM,
- Hash: crypto.SHA256,
- KeyLen: 16,
- IvLen: 12,
- },
- TLS_AES_256_GCM_SHA384: {
- Suite: TLS_AES_256_GCM_SHA384,
- Cipher: newAESGCM,
- Hash: crypto.SHA384,
- KeyLen: 32,
- IvLen: 12,
- },
- }
- x509AlgMap = map[SignatureScheme]x509.SignatureAlgorithm{
- RSA_PKCS1_SHA1: x509.SHA1WithRSA,
- RSA_PKCS1_SHA256: x509.SHA256WithRSA,
- RSA_PKCS1_SHA384: x509.SHA384WithRSA,
- RSA_PKCS1_SHA512: x509.SHA512WithRSA,
- ECDSA_P256_SHA256: x509.ECDSAWithSHA256,
- ECDSA_P384_SHA384: x509.ECDSAWithSHA384,
- ECDSA_P521_SHA512: x509.ECDSAWithSHA512,
- }
- defaultRSAKeySize = 2048
- )
- func curveFromNamedGroup(group NamedGroup) (crv elliptic.Curve) {
- switch group {
- case P256:
- crv = elliptic.P256()
- case P384:
- crv = elliptic.P384()
- case P521:
- crv = elliptic.P521()
- }
- return
- }
- func namedGroupFromECDSAKey(key *ecdsa.PublicKey) (g NamedGroup) {
- switch key.Curve.Params().Name {
- case elliptic.P256().Params().Name:
- g = P256
- case elliptic.P384().Params().Name:
- g = P384
- case elliptic.P521().Params().Name:
- g = P521
- }
- return
- }
- func keyExchangeSizeFromNamedGroup(group NamedGroup) (size int) {
- size = 0
- switch group {
- case X25519:
- size = 32
- case P256:
- size = 65
- case P384:
- size = 97
- case P521:
- size = 133
- case FFDHE2048:
- size = 256
- case FFDHE3072:
- size = 384
- case FFDHE4096:
- size = 512
- case FFDHE6144:
- size = 768
- case FFDHE8192:
- size = 1024
- }
- return
- }
- func primeFromNamedGroup(group NamedGroup) (p *big.Int) {
- switch group {
- case FFDHE2048:
- p = finiteFieldPrime2048
- case FFDHE3072:
- p = finiteFieldPrime3072
- case FFDHE4096:
- p = finiteFieldPrime4096
- case FFDHE6144:
- p = finiteFieldPrime6144
- case FFDHE8192:
- p = finiteFieldPrime8192
- }
- return
- }
- func schemeValidForKey(alg SignatureScheme, key crypto.Signer) bool {
- sigType := sigMap[alg]
- switch key.(type) {
- case *rsa.PrivateKey:
- return sigType == signatureAlgorithmRSA_PKCS1 || sigType == signatureAlgorithmRSA_PSS
- case *ecdsa.PrivateKey:
- return sigType == signatureAlgorithmECDSA
- default:
- return false
- }
- }
- func ffdheKeyShareFromPrime(p *big.Int) (priv, pub *big.Int, err error) {
- primeLen := len(p.Bytes())
- for {
- // g = 2 for all ffdhe groups
- priv, err = rand.Int(prng, p)
- if err != nil {
- return
- }
- pub = big.NewInt(0)
- pub.Exp(big.NewInt(2), priv, p)
- if len(pub.Bytes()) == primeLen {
- return
- }
- }
- }
- func newKeyShare(group NamedGroup) (pub []byte, priv []byte, err error) {
- switch group {
- case P256, P384, P521:
- var x, y *big.Int
- crv := curveFromNamedGroup(group)
- priv, x, y, err = elliptic.GenerateKey(crv, prng)
- if err != nil {
- return
- }
- pub = elliptic.Marshal(crv, x, y)
- return
- case FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192:
- p := primeFromNamedGroup(group)
- x, X, err2 := ffdheKeyShareFromPrime(p)
- if err2 != nil {
- err = err2
- return
- }
- priv = x.Bytes()
- pubBytes := X.Bytes()
- numBytes := keyExchangeSizeFromNamedGroup(group)
- pub = make([]byte, numBytes)
- copy(pub[numBytes-len(pubBytes):], pubBytes)
- return
- case X25519:
- var private, public [32]byte
- _, err = prng.Read(private[:])
- if err != nil {
- return
- }
- curve25519.ScalarBaseMult(&public, &private)
- priv = private[:]
- pub = public[:]
- return
- default:
- return nil, nil, fmt.Errorf("tls.newkeyshare: Unsupported group %v", group)
- }
- }
- func keyAgreement(group NamedGroup, pub []byte, priv []byte) ([]byte, error) {
- switch group {
- case P256, P384, P521:
- if len(pub) != keyExchangeSizeFromNamedGroup(group) {
- return nil, fmt.Errorf("tls.keyagreement: Wrong public key size")
- }
- crv := curveFromNamedGroup(group)
- pubX, pubY := elliptic.Unmarshal(crv, pub)
- x, _ := crv.Params().ScalarMult(pubX, pubY, priv)
- xBytes := x.Bytes()
- numBytes := len(crv.Params().P.Bytes())
- ret := make([]byte, numBytes)
- copy(ret[numBytes-len(xBytes):], xBytes)
- return ret, nil
- case FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192:
- numBytes := keyExchangeSizeFromNamedGroup(group)
- if len(pub) != numBytes {
- return nil, fmt.Errorf("tls.keyagreement: Wrong public key size")
- }
- p := primeFromNamedGroup(group)
- x := big.NewInt(0).SetBytes(priv)
- Y := big.NewInt(0).SetBytes(pub)
- ZBytes := big.NewInt(0).Exp(Y, x, p).Bytes()
- ret := make([]byte, numBytes)
- copy(ret[numBytes-len(ZBytes):], ZBytes)
- return ret, nil
- case X25519:
- if len(pub) != keyExchangeSizeFromNamedGroup(group) {
- return nil, fmt.Errorf("tls.keyagreement: Wrong public key size")
- }
- var private, public, ret [32]byte
- copy(private[:], priv)
- copy(public[:], pub)
- curve25519.ScalarMult(&ret, &private, &public)
- return ret[:], nil
- default:
- return nil, fmt.Errorf("tls.keyagreement: Unsupported group %v", group)
- }
- }
- func newSigningKey(sig SignatureScheme) (crypto.Signer, error) {
- switch sig {
- case RSA_PKCS1_SHA1, RSA_PKCS1_SHA256,
- RSA_PKCS1_SHA384, RSA_PKCS1_SHA512,
- RSA_PSS_SHA256, RSA_PSS_SHA384,
- RSA_PSS_SHA512:
- return rsa.GenerateKey(prng, defaultRSAKeySize)
- case ECDSA_P256_SHA256:
- return ecdsa.GenerateKey(elliptic.P256(), prng)
- case ECDSA_P384_SHA384:
- return ecdsa.GenerateKey(elliptic.P384(), prng)
- case ECDSA_P521_SHA512:
- return ecdsa.GenerateKey(elliptic.P521(), prng)
- default:
- return nil, fmt.Errorf("tls.newsigningkey: Unsupported signature algorithm [%04x]", sig)
- }
- }
- // XXX(rlb): Copied from crypto/x509
- type ecdsaSignature struct {
- R, S *big.Int
- }
- func sign(alg SignatureScheme, privateKey crypto.Signer, sigInput []byte) ([]byte, error) {
- var opts crypto.SignerOpts
- hash := hashMap[alg]
- if hash == crypto.SHA1 {
- return nil, fmt.Errorf("tls.crypt.sign: Use of SHA-1 is forbidden")
- }
- sigType := sigMap[alg]
- var realInput []byte
- switch key := privateKey.(type) {
- case *rsa.PrivateKey:
- switch {
- case allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1:
- logf(logTypeCrypto, "signing with PKCS1, hashSize=[%d]", hash.Size())
- opts = hash
- case !allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1:
- fallthrough
- case sigType == signatureAlgorithmRSA_PSS:
- logf(logTypeCrypto, "signing with PSS, hashSize=[%d]", hash.Size())
- opts = &rsa.PSSOptions{SaltLength: hash.Size(), Hash: hash}
- default:
- return nil, fmt.Errorf("tls.crypto.sign: Unsupported algorithm for RSA key")
- }
- h := hash.New()
- h.Write(sigInput)
- realInput = h.Sum(nil)
- case *ecdsa.PrivateKey:
- if sigType != signatureAlgorithmECDSA {
- return nil, fmt.Errorf("tls.crypto.sign: Unsupported algorithm for ECDSA key")
- }
- algGroup := curveMap[alg]
- keyGroup := namedGroupFromECDSAKey(key.Public().(*ecdsa.PublicKey))
- if algGroup != keyGroup {
- return nil, fmt.Errorf("tls.crypto.sign: Unsupported hash/curve combination")
- }
- h := hash.New()
- h.Write(sigInput)
- realInput = h.Sum(nil)
- default:
- return nil, fmt.Errorf("tls.crypto.sign: Unsupported private key type")
- }
- sig, err := privateKey.Sign(prng, realInput, opts)
- logf(logTypeCrypto, "signature: %x", sig)
- return sig, err
- }
- func verify(alg SignatureScheme, publicKey crypto.PublicKey, sigInput []byte, sig []byte) error {
- hash := hashMap[alg]
- if hash == crypto.SHA1 {
- return fmt.Errorf("tls.crypt.sign: Use of SHA-1 is forbidden")
- }
- sigType := sigMap[alg]
- switch pub := publicKey.(type) {
- case *rsa.PublicKey:
- switch {
- case allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1:
- logf(logTypeCrypto, "verifying with PKCS1, hashSize=[%d]", hash.Size())
- h := hash.New()
- h.Write(sigInput)
- realInput := h.Sum(nil)
- return rsa.VerifyPKCS1v15(pub, hash, realInput, sig)
- case !allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1:
- fallthrough
- case sigType == signatureAlgorithmRSA_PSS:
- logf(logTypeCrypto, "verifying with PSS, hashSize=[%d]", hash.Size())
- opts := &rsa.PSSOptions{SaltLength: hash.Size(), Hash: hash}
- h := hash.New()
- h.Write(sigInput)
- realInput := h.Sum(nil)
- return rsa.VerifyPSS(pub, hash, realInput, sig, opts)
- default:
- return fmt.Errorf("tls.verify: Unsupported algorithm for RSA key")
- }
- case *ecdsa.PublicKey:
- if sigType != signatureAlgorithmECDSA {
- return fmt.Errorf("tls.verify: Unsupported algorithm for ECDSA key")
- }
- if curveMap[alg] != namedGroupFromECDSAKey(pub) {
- return fmt.Errorf("tls.verify: Unsupported curve for ECDSA key")
- }
- ecdsaSig := new(ecdsaSignature)
- if rest, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
- return err
- } else if len(rest) != 0 {
- return fmt.Errorf("tls.verify: trailing data after ECDSA signature")
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return fmt.Errorf("tls.verify: ECDSA signature contained zero or negative values")
- }
- h := hash.New()
- h.Write(sigInput)
- realInput := h.Sum(nil)
- if !ecdsa.Verify(pub, realInput, ecdsaSig.R, ecdsaSig.S) {
- return fmt.Errorf("tls.verify: ECDSA verification failure")
- }
- return nil
- default:
- return fmt.Errorf("tls.verify: Unsupported key type")
- }
- }
- // 0
- // |
- // v
- // PSK -> HKDF-Extract = Early Secret
- // |
- // +-----> Derive-Secret(.,
- // | "ext binder" |
- // | "res binder",
- // | "")
- // | = binder_key
- // |
- // +-----> Derive-Secret(., "c e traffic",
- // | ClientHello)
- // | = client_early_traffic_secret
- // |
- // +-----> Derive-Secret(., "e exp master",
- // | ClientHello)
- // | = early_exporter_master_secret
- // v
- // Derive-Secret(., "derived", "")
- // |
- // v
- // (EC)DHE -> HKDF-Extract = Handshake Secret
- // |
- // +-----> Derive-Secret(., "c hs traffic",
- // | ClientHello...ServerHello)
- // | = client_handshake_traffic_secret
- // |
- // +-----> Derive-Secret(., "s hs traffic",
- // | ClientHello...ServerHello)
- // | = server_handshake_traffic_secret
- // v
- // Derive-Secret(., "derived", "")
- // |
- // v
- // 0 -> HKDF-Extract = Master Secret
- // |
- // +-----> Derive-Secret(., "c ap traffic",
- // | ClientHello...server Finished)
- // | = client_application_traffic_secret_0
- // |
- // +-----> Derive-Secret(., "s ap traffic",
- // | ClientHello...server Finished)
- // | = server_application_traffic_secret_0
- // |
- // +-----> Derive-Secret(., "exp master",
- // | ClientHello...server Finished)
- // | = exporter_master_secret
- // |
- // +-----> Derive-Secret(., "res master",
- // ClientHello...client Finished)
- // = resumption_master_secret
- // From RFC 5869
- // PRK = HMAC-Hash(salt, IKM)
- func HkdfExtract(hash crypto.Hash, saltIn, input []byte) []byte {
- salt := saltIn
- // if [salt is] not provided, it is set to a string of HashLen zeros
- if salt == nil {
- salt = bytes.Repeat([]byte{0}, hash.Size())
- }
- h := hmac.New(hash.New, salt)
- h.Write(input)
- out := h.Sum(nil)
- logf(logTypeCrypto, "HKDF Extract:\n")
- logf(logTypeCrypto, "Salt [%d]: %x\n", len(salt), salt)
- logf(logTypeCrypto, "Input [%d]: %x\n", len(input), input)
- logf(logTypeCrypto, "Output [%d]: %x\n", len(out), out)
- return out
- }
- const (
- labelExternalBinder = "ext binder"
- labelResumptionBinder = "res binder"
- labelEarlyTrafficSecret = "c e traffic"
- labelEarlyExporterSecret = "e exp master"
- labelClientHandshakeTrafficSecret = "c hs traffic"
- labelServerHandshakeTrafficSecret = "s hs traffic"
- labelClientApplicationTrafficSecret = "c ap traffic"
- labelServerApplicationTrafficSecret = "s ap traffic"
- labelExporterSecret = "exp master"
- labelResumptionSecret = "res master"
- labelDerived = "derived"
- labelFinished = "finished"
- labelResumption = "resumption"
- )
- // struct HkdfLabel {
- // uint16 length;
- // opaque label<9..255>;
- // opaque hash_value<0..255>;
- // };
- func hkdfEncodeLabel(labelIn string, hashValue []byte, outLen int) []byte {
- label := "tls13 " + labelIn
- labelLen := len(label)
- hashLen := len(hashValue)
- hkdfLabel := make([]byte, 2+1+labelLen+1+hashLen)
- hkdfLabel[0] = byte(outLen >> 8)
- hkdfLabel[1] = byte(outLen)
- hkdfLabel[2] = byte(labelLen)
- copy(hkdfLabel[3:3+labelLen], []byte(label))
- hkdfLabel[3+labelLen] = byte(hashLen)
- copy(hkdfLabel[3+labelLen+1:], hashValue)
- return hkdfLabel
- }
- func HkdfExpand(hash crypto.Hash, prk, info []byte, outLen int) []byte {
- out := []byte{}
- T := []byte{}
- i := byte(1)
- for len(out) < outLen {
- block := append(T, info...)
- block = append(block, i)
- h := hmac.New(hash.New, prk)
- h.Write(block)
- T = h.Sum(nil)
- out = append(out, T...)
- i++
- }
- return out[:outLen]
- }
- func HkdfExpandLabel(hash crypto.Hash, secret []byte, label string, hashValue []byte, outLen int) []byte {
- info := hkdfEncodeLabel(label, hashValue, outLen)
- derived := HkdfExpand(hash, secret, info, outLen)
- logf(logTypeCrypto, "HKDF Expand: label=[tls13 ] + '%s',requested length=%d\n", label, outLen)
- logf(logTypeCrypto, "PRK [%d]: %x\n", len(secret), secret)
- logf(logTypeCrypto, "Hash [%d]: %x\n", len(hashValue), hashValue)
- logf(logTypeCrypto, "Info [%d]: %x\n", len(info), info)
- logf(logTypeCrypto, "Derived key [%d]: %x\n", len(derived), derived)
- return derived
- }
- func deriveSecret(params CipherSuiteParams, secret []byte, label string, messageHash []byte) []byte {
- return HkdfExpandLabel(params.Hash, secret, label, messageHash, params.Hash.Size())
- }
- func computeFinishedData(params CipherSuiteParams, baseKey []byte, input []byte) []byte {
- macKey := HkdfExpandLabel(params.Hash, baseKey, labelFinished, []byte{}, params.Hash.Size())
- mac := hmac.New(params.Hash.New, macKey)
- mac.Write(input)
- return mac.Sum(nil)
- }
- type keySet struct {
- cipher aeadFactory
- key []byte
- iv []byte
- }
- func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet {
- logf(logTypeCrypto, "making traffic keys: secret=%x", secret)
- return keySet{
- cipher: params.Cipher,
- key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen),
- iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
- }
- }
- func MakeNewSelfSignedCert(name string, alg SignatureScheme) (crypto.Signer, *x509.Certificate, error) {
- priv, err := newSigningKey(alg)
- if err != nil {
- return nil, nil, err
- }
- cert, err := newSelfSigned(name, alg, priv)
- if err != nil {
- return nil, nil, err
- }
- return priv, cert, nil
- }
- func newSelfSigned(name string, alg SignatureScheme, priv crypto.Signer) (*x509.Certificate, error) {
- sigAlg, ok := x509AlgMap[alg]
- if !ok {
- return nil, fmt.Errorf("tls.selfsigned: Unknown signature algorithm [%04x]", alg)
- }
- if len(name) == 0 {
- return nil, fmt.Errorf("tls.selfsigned: No name provided")
- }
- serial, err := rand.Int(rand.Reader, big.NewInt(0xA0A0A0A0))
- if err != nil {
- return nil, err
- }
- template := &x509.Certificate{
- SerialNumber: serial,
- NotBefore: time.Now(),
- NotAfter: time.Now().AddDate(0, 0, 1),
- SignatureAlgorithm: sigAlg,
- Subject: pkix.Name{CommonName: name},
- DNSNames: []string{name},
- KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- }
- der, err := x509.CreateCertificate(prng, template, template, priv.Public(), priv)
- if err != nil {
- return nil, err
- }
- // It is safe to ignore the error here because we're parsing known-good data
- cert, _ := x509.ParseCertificate(der)
- return cert, nil
- }
|