diff options
author | David Benjamin <davidben@chromium.org> | 2014-10-27 02:23:15 -0400 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2014-10-29 20:33:09 +0000 |
commit | 2af684fa92a4bab4f59da12b58b03cd15b963623 (patch) | |
tree | adfca255891a0a7fb52b0b8e3878bb3f8fb4e10c | |
parent | 491956c8668a4a5da13120212a10b0c3183dec63 (diff) | |
download | src-2af684fa92a4bab4f59da12b58b03cd15b963623.tar.gz |
Add tests for ECDHE_PSK.
pskKeyAgreement is now a wrapper over a base key agreement.
Change-Id: Ic18862d3e98f7513476f878b8df5dcd8d36a0eac
Reviewed-on: https://boringssl-review.googlesource.com/2053
Reviewed-by: Adam Langley <agl@google.com>
-rw-r--r-- | ssl/test/runner/cipher_suites.go | 24 | ||||
-rw-r--r-- | ssl/test/runner/key_agreement.go | 139 | ||||
-rw-r--r-- | ssl/test/runner/runner.go | 1 |
3 files changed, 138 insertions, 26 deletions
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go index a0e6b94..5a3ac80 100644 --- a/ssl/test/runner/cipher_suites.go +++ b/ssl/test/runner/cipher_suites.go @@ -112,6 +112,7 @@ var cipherSuites = []*cipherSuite{ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil}, {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, + {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM}, {TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil}, {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, @@ -293,7 +294,7 @@ func rsaKA(version uint16) keyAgreement { func ecdheECDSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureECDSA, version: version, }, @@ -302,7 +303,7 @@ func ecdheECDSAKA(version uint16) keyAgreement { func ecdheRSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureRSA, version: version, }, @@ -311,7 +312,7 @@ func ecdheRSAKA(version uint16) keyAgreement { func dheRSAKA(version uint16) keyAgreement { return &dheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureRSA, version: version, }, @@ -319,7 +320,17 @@ func dheRSAKA(version uint16) keyAgreement { } func pskKA(version uint16) keyAgreement { - return &pskKeyAgreement{} + return &pskKeyAgreement{ + base: &nilKeyAgreement{}, + } +} + +func ecdhePSKKA(version uint16) keyAgreement { + return &pskKeyAgreement{ + base: &ecdheKeyAgreement{ + auth: &nilKeyAgreementAuthentication{}, + }, + } } // mutualCipherSuite returns a cipherSuite given a list of supported @@ -377,3 +388,8 @@ const ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 fallbackSCSV uint16 = 0x5600 ) + +// Additional cipher suite IDs, not IANA-assigned. +const ( + TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe +) diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go index 4f76cb1..af54a8f 100644 --- a/ssl/test/runner/key_agreement.go +++ b/ssl/test/runner/key_agreement.go @@ -187,8 +187,29 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) { } -// signedKeyAgreement implements helper functions for key agreement -// methods that involve signed parameters in the ServerKeyExchange. +// keyAgreementAuthentication is a helper interface that specifies how +// to authenticate the ServerKeyExchange parameters. +type keyAgreementAuthentication interface { + signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) + verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error +} + +// nilKeyAgreementAuthentication does not authenticate the key +// agreement parameters. +type nilKeyAgreementAuthentication struct{} + +func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { + skx := new(serverKeyExchangeMsg) + skx.key = params + return skx, nil +} + +func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error { + return nil +} + +// signedKeyAgreement signs the ServerKeyExchange parameters with the +// server's private key. type signedKeyAgreement struct { version uint16 sigType uint8 @@ -328,7 +349,7 @@ func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clie // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { - signedKeyAgreement + auth keyAgreementAuthentication privateKey []byte curve elliptic.Curve x, y *big.Int @@ -394,7 +415,7 @@ NextCandidate: serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - return ka.signParameters(config, cert, clientHello, hello, serverECDHParams) + return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams) } func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { @@ -438,7 +459,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell serverECDHParams := skx.key[:4+publicLen] sig := skx.key[4+publicLen:] - return ka.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig) + return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig) } func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { @@ -468,7 +489,7 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel // an ephemeral Diffie-Hellman public/private key pair and signs it. The // pre-master secret is then calculated using Diffie-Hellman. type dheKeyAgreement struct { - signedKeyAgreement + auth keyAgreementAuthentication p, g *big.Int yTheirs *big.Int xOurs *big.Int @@ -500,7 +521,7 @@ func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes))) serverDHParams = append(serverDHParams, yBytes...) - return ka.signParameters(config, cert, clientHello, hello, serverDHParams) + return ka.auth.signParameters(config, cert, clientHello, hello, serverDHParams) } func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { @@ -562,7 +583,7 @@ func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello sig := k serverDHParams := skx.key[:len(skx.key)-len(sig)] - return ka.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig) + return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig) } func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { @@ -587,8 +608,43 @@ func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello return preMasterSecret, ckx, nil } -// makePSKPremaster formats a PSK pre-master secret based on -// otherSecret from the base key exchange and psk. +// nilKeyAgreement is a fake key agreement used to implement the plain PSK key +// exchange. +type nilKeyAgreement struct{} + +func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + return nil, nil +} + +func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) != 0 { + return nil, errClientKeyExchange + } + + // Although in plain PSK, otherSecret is all zeros, the base key + // agreement does not access to the length of the pre-shared + // key. pskKeyAgreement instead interprets nil to mean to use all zeros + // of the appropriate length. + return nil, nil +} + +func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + if len(skx.key) != 0 { + return errServerKeyExchange + } + return nil +} + +func (ka *nilKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + // Although in plain PSK, otherSecret is all zeros, the base key + // agreement does not access to the length of the pre-shared + // key. pskKeyAgreement instead interprets nil to mean to use all zeros + // of the appropriate length. + return nil, &clientKeyExchangeMsg{}, nil +} + +// makePSKPremaster formats a PSK pre-master secret based on otherSecret from +// the base key exchange and psk. func makePSKPremaster(otherSecret, psk []byte) []byte { out := make([]byte, 0, 2+len(otherSecret)+2+len(psk)) out = append(out, byte(len(otherSecret)>>8), byte(len(otherSecret))) @@ -600,33 +656,47 @@ func makePSKPremaster(otherSecret, psk []byte) []byte { // pskKeyAgreement implements the PSK key agreement. type pskKeyAgreement struct { + base keyAgreement identityHint string } func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - // ServerKeyExchange is optional if the identity hint is empty. - if config.PreSharedKeyIdentity == "" { - return nil, nil - } + // Assemble the identity hint. bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) bytes[1] = byte(len(config.PreSharedKeyIdentity)) copy(bytes[2:], []byte(config.PreSharedKeyIdentity)) + // If there is one, append the base key agreement's + // ServerKeyExchange. + baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello) + if err != nil { + return nil, err + } + + if baseSkx != nil { + bytes = append(bytes, baseSkx.key...) + } else if config.PreSharedKeyIdentity == "" { + // ServerKeyExchange is optional if the identity hint is empty + // and there would otherwise be no ServerKeyExchange. + return nil, nil + } + skx := new(serverKeyExchangeMsg) skx.key = bytes return skx, nil } func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + // First, process the PSK identity. if len(ckx.ciphertext) < 2 { return nil, errClientKeyExchange } identityLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1]) - if 2+identityLen != len(ckx.ciphertext) { + if 2+identityLen > len(ckx.ciphertext) { return nil, errClientKeyExchange } - identity := string(ckx.ciphertext[2:]) + identity := string(ckx.ciphertext[2 : 2+identityLen]) if identity != config.PreSharedKeyIdentity { return nil, errors.New("tls: unexpected identity") @@ -635,7 +705,20 @@ func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certif if config.PreSharedKey == nil { return nil, errors.New("tls: pre-shared key not configured") } - otherSecret := make([]byte, len(config.PreSharedKey)) + + // Process the remainder of the ClientKeyExchange to compute the base + // pre-master secret. + newCkx := new(clientKeyExchangeMsg) + newCkx.ciphertext = ckx.ciphertext[2+identityLen:] + otherSecret, err := ka.base.processClientKeyExchange(config, cert, newCkx, version) + if err != nil { + return nil, err + } + + if otherSecret == nil { + // Special-case for the plain PSK key exchanges. + otherSecret = make([]byte, len(config.PreSharedKey)) + } return makePSKPremaster(otherSecret, config.PreSharedKey), nil } @@ -644,11 +727,15 @@ func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello return errServerKeyExchange } identityLen := (int(skx.key[0]) << 8) | int(skx.key[1]) - if 2+identityLen != len(skx.key) { + if 2+identityLen > len(skx.key) { return errServerKeyExchange } - ka.identityHint = string(skx.key[2:]) - return nil + ka.identityHint = string(skx.key[2 : 2+identityLen]) + + // Process the remainder of the ServerKeyExchange. + newSkx := new(serverKeyExchangeMsg) + newSkx.key = skx.key[2+identityLen:] + return ka.base.processServerKeyExchange(config, clientHello, serverHello, cert, newSkx) } func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { @@ -659,17 +746,25 @@ func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello return nil, nil, errors.New("tls: unexpected identity") } + // Serialize the identity. bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) bytes[1] = byte(len(config.PreSharedKeyIdentity)) copy(bytes[2:], []byte(config.PreSharedKeyIdentity)) + // Append the base key exchange's ClientKeyExchange. + otherSecret, baseCkx, err := ka.base.generateClientKeyExchange(config, clientHello, cert) + if err != nil { + return nil, nil, err + } ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = bytes + ckx.ciphertext = append(bytes, baseCkx.ciphertext...) if config.PreSharedKey == nil { return nil, nil, errors.New("tls: pre-shared key not configured") } - otherSecret := make([]byte, len(config.PreSharedKey)) + if otherSecret == nil { + otherSecret = make([]byte, len(config.PreSharedKey)) + } return makePSKPremaster(otherSecret, config.PreSharedKey), ckx, nil } diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 6f4562a..1b461e2 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -828,6 +828,7 @@ var testCipherSuites = []struct { {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, + {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256}, {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, |