ecdhePublic := params .PublicKey ()
serverECDHEParams := make ([]byte , 1 +2 +1 +len (ecdhePublic ))
serverECDHEParams [0 ] = 3
serverECDHEParams [1 ] = byte (curveID >> 8 )
serverECDHEParams [2 ] = byte (curveID )
serverECDHEParams [3 ] = byte (len (ecdhePublic ))
copy (serverECDHEParams [4 :], ecdhePublic )
priv , ok := cert .PrivateKey .(crypto .Signer )
if !ok {
return nil , fmt .Errorf ("tls: certificate private key of type %T does not implement crypto.Signer" , cert .PrivateKey )
}
var signatureAlgorithm SignatureScheme
var sigType uint8
var sigHash crypto .Hash
if ka .version >= VersionTLS12 {
signatureAlgorithm , err = selectSignatureScheme (ka .version , cert , clientHello .supportedSignatureAlgorithms )
if err != nil {
return nil , err
}
sigType , sigHash , err = typeAndHashFromSignatureScheme (signatureAlgorithm )
if err != nil {
return nil , err
}
} else {
sigType , sigHash , err = legacyTypeAndHashFromPublicKey (priv .Public ())
if err != nil {
return nil , err
}
}
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS ) != ka .isRSA {
return nil , errors .New ("tls: certificate cannot be used with the selected cipher suite" )
}
signed := hashForServerKeyExchange (sigType , sigHash , ka .version , clientHello .random , hello .random , serverECDHEParams )
signOpts := crypto .SignerOpts (sigHash )
if sigType == signatureRSAPSS {
signOpts = &rsa .PSSOptions {SaltLength : rsa .PSSSaltLengthEqualsHash , Hash : sigHash }
}
sig , err := priv .Sign (config .rand (), signed , signOpts )
if err != nil {
return nil , errors .New ("tls: failed to sign ECDHE parameters: " + err .Error())
}
skx := new (serverKeyExchangeMsg )
sigAndHashLen := 0
if ka .version >= VersionTLS12 {
sigAndHashLen = 2
}
skx .key = make ([]byte , len (serverECDHEParams )+sigAndHashLen +2 +len (sig ))
copy (skx .key , serverECDHEParams )
k := skx .key [len (serverECDHEParams ):]
if ka .version >= VersionTLS12 {
k [0 ] = byte (signatureAlgorithm >> 8 )
k [1 ] = byte (signatureAlgorithm )
k = k [2 :]
}
k [0 ] = byte (len (sig ) >> 8 )
k [1 ] = byte (len (sig ))
copy (k [2 :], sig )
return skx , nil
}
func (ka *ecdheKeyAgreement ) processClientKeyExchange (config *Config , cert *Certificate , ckx *clientKeyExchangeMsg , version uint16 ) ([]byte , error ) {
if len (ckx .ciphertext ) == 0 || int (ckx .ciphertext [0 ]) != len (ckx .ciphertext )-1 {
return nil , errClientKeyExchange
}
preMasterSecret := ka .params .SharedKey (ckx .ciphertext [1 :])
if preMasterSecret == nil {
return nil , errClientKeyExchange
}
return preMasterSecret , nil
}
func (ka *ecdheKeyAgreement ) processServerKeyExchange (config *Config , clientHello *clientHelloMsg , serverHello *serverHelloMsg , cert *x509 .Certificate , skx *serverKeyExchangeMsg ) error {
if len (skx .key ) < 4 {
return errServerKeyExchange
}
if skx .key [0 ] != 3 {
return errors .New ("tls: server selected unsupported curve" )
}
curveID := CurveID (skx .key [1 ])<<8 | CurveID (skx .key [2 ])
publicLen := int (skx .key [3 ])
if publicLen +4 > len (skx .key ) {
return errServerKeyExchange
}
serverECDHEParams := skx .key [:4 +publicLen ]
publicKey := serverECDHEParams [4 :]
sig := skx .key [4 +publicLen :]
if len (sig ) < 2 {
return errServerKeyExchange
}
if _ , ok := curveForCurveID (curveID ); curveID != X25519 && !ok {
return errors .New ("tls: server selected unsupported curve" )
}
params , err := generateECDHEParameters (config .rand (), curveID )
if err != nil {
return err
}
ka .params = params
ka .preMasterSecret = params .SharedKey (publicKey )
if ka .preMasterSecret == nil {
return errServerKeyExchange
}
ourPublicKey := params .PublicKey ()
ka .ckx = new (clientKeyExchangeMsg )
ka .ckx .ciphertext = make ([]byte , 1 +len (ourPublicKey ))
ka .ckx .ciphertext [0 ] = byte (len (ourPublicKey ))
copy (ka .ckx .ciphertext [1 :], ourPublicKey )
var sigType uint8
var sigHash crypto .Hash
if ka .version >= VersionTLS12 {
signatureAlgorithm := SignatureScheme (sig [0 ])<<8 | SignatureScheme (sig [1 ])
sig = sig [2 :]
if len (sig ) < 2 {
return errServerKeyExchange
}
if !isSupportedSignatureAlgorithm (signatureAlgorithm , clientHello .supportedSignatureAlgorithms ) {
return errors .New ("tls: certificate used with invalid signature algorithm" )
}
sigType , sigHash , err = typeAndHashFromSignatureScheme (signatureAlgorithm )
if err != nil {
return err
}
} else {
sigType , sigHash , err = legacyTypeAndHashFromPublicKey (cert .PublicKey )
if err != nil {
return err
}
}
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS ) != ka .isRSA {
return errServerKeyExchange
}
sigLen := int (sig [0 ])<<8 | int (sig [1 ])
if sigLen +2 != len (sig ) {
return errServerKeyExchange
}
sig = sig [2 :]
signed := hashForServerKeyExchange (sigType , sigHash , ka .version , clientHello .random , serverHello .random , serverECDHEParams )
if err := verifyHandshakeSignature (sigType , cert .PublicKey , sigHash , signed , sig ); err != nil {
return errors .New ("tls: invalid signature by the server certificate: " + err .Error())
}
return nil
}
func (ka *ecdheKeyAgreement ) generateClientKeyExchange (config *Config , clientHello *clientHelloMsg , cert *x509 .Certificate ) ([]byte , *clientKeyExchangeMsg , error ) {
if ka .ckx == nil {
return nil , nil , errors .New ("tls: missing ServerKeyExchange message" )
}
return ka .preMasterSecret , ka .ckx , nil