package  tlsimport  (	"crypto" 	"crypto/ecdh" 	"crypto/md5" 	"crypto/rsa" 	"crypto/sha1" 	"crypto/x509" 	"errors" 	"fmt" 	"io" )type  keyAgreement  interface  {			generateServerKeyExchange (*Config , *Certificate , *clientHelloMsg , *serverHelloMsg ) (*serverKeyExchangeMsg , error )	processClientKeyExchange (*Config , *Certificate , *clientKeyExchangeMsg , uint16 ) ([]byte , error )			processServerKeyExchange (*Config , *clientHelloMsg , *serverHelloMsg , *x509 .Certificate , *serverKeyExchangeMsg ) error 	generateClientKeyExchange (*Config , *clientHelloMsg , *x509 .Certificate ) ([]byte , *clientKeyExchangeMsg , error )}var  errClientKeyExchange  = errors .New ("tls: invalid ClientKeyExchange message" )var  errServerKeyExchange  = errors .New ("tls: invalid ServerKeyExchange message" )type  rsaKeyAgreement  struct {}func  (ka  rsaKeyAgreement ) generateServerKeyExchange config  *Config , cert  *Certificate , clientHello  *clientHelloMsg , hello  *serverHelloMsg ) (*serverKeyExchangeMsg , error ) {	return  nil , nil }func  (ka  rsaKeyAgreement ) processClientKeyExchange config  *Config , cert  *Certificate , ckx  *clientKeyExchangeMsg , version  uint16 ) ([]byte , error ) {	if  len (ckx .ciphertext ) < 2  {		return  nil , errClientKeyExchange 	}	ciphertextLen  := int (ckx .ciphertext [0 ])<<8  | int (ckx .ciphertext [1 ])	if  ciphertextLen  != len (ckx .ciphertext )-2  {		return  nil , errClientKeyExchange 	}	ciphertext  := ckx .ciphertext [2 :]	priv , ok  := cert .PrivateKey .(crypto .Decrypter )	if  !ok  {		return  nil , errors .New ("tls: certificate private key does not implement crypto.Decrypter" )	}		preMasterSecret , err  := priv .Decrypt (config .rand (), ciphertext , &rsa .PKCS1v15DecryptOptions {SessionKeyLen : 48 })	if  err  != nil  {		return  nil , err 	}		return  preMasterSecret , nil }func  (ka  rsaKeyAgreement ) processServerKeyExchange config  *Config , clientHello  *clientHelloMsg , serverHello  *serverHelloMsg , cert  *x509 .Certificate , skx  *serverKeyExchangeMsg ) error  {	return  errors .New ("tls: unexpected ServerKeyExchange" )}func  (ka  rsaKeyAgreement ) generateClientKeyExchange config  *Config , clientHello  *clientHelloMsg , cert  *x509 .Certificate ) ([]byte , *clientKeyExchangeMsg , error ) {	preMasterSecret  := make ([]byte , 48 )	preMasterSecret [0 ] = byte (clientHello .vers  >> 8 )	preMasterSecret [1 ] = byte (clientHello .vers )	_ , err  := io .ReadFull (config .rand (), preMasterSecret [2 :])	if  err  != nil  {		return  nil , nil , err 	}	rsaKey , ok  := cert .PublicKey .(*rsa .PublicKey )	if  !ok  {		return  nil , nil , errors .New ("tls: server certificate contains incorrect key type for selected ciphersuite" )	}	encrypted , err  := rsa .EncryptPKCS1v15 (config .rand (), rsaKey , preMasterSecret )	if  err  != nil  {		return  nil , nil , err 	}	ckx  := new (clientKeyExchangeMsg )	ckx .ciphertext  = make ([]byte , len (encrypted )+2 )	ckx .ciphertext [0 ] = byte (len (encrypted ) >> 8 )	ckx .ciphertext [1 ] = byte (len (encrypted ))	copy (ckx .ciphertext [2 :], encrypted )	return  preMasterSecret , ckx , nil }func  sha1Hash slices  [][]byte ) []byte  {	hsha1  := sha1 .New ()	for  _ , slice  := range  slices  {		hsha1 .Write (slice )	}	return  hsha1 .Sum (nil )}func  md5SHA1Hash slices  [][]byte ) []byte  {	md5sha1  := make ([]byte , md5 .Size +sha1 .Size )	hmd5  := md5 .New ()	for  _ , slice  := range  slices  {		hmd5 .Write (slice )	}	copy (md5sha1 , hmd5 .Sum (nil ))	copy (md5sha1 [md5 .Size :], sha1Hash (slices ))	return  md5sha1 }func  hashForServerKeyExchange sigType  uint8 , hashFunc  crypto .Hash , version  uint16 , slices  ...[]byte ) []byte  {	if  sigType  == signatureEd25519  {		var  signed  []byte 		for  _ , slice  := range  slices  {			signed  = append (signed , slice ...)		}		return  signed 	}	if  version  >= VersionTLS12  {		h  := hashFunc .New ()		for  _ , slice  := range  slices  {			h .Write (slice )		}		digest  := h .Sum (nil )		return  digest 	}	if  sigType  == signatureECDSA  {		return  sha1Hash (slices )	}	return  md5SHA1Hash (slices )}type  ecdheKeyAgreement  struct  {	version  uint16 	isRSA    bool 	key      *ecdh .PrivateKey 		ckx              *clientKeyExchangeMsg 	preMasterSecret  []byte }func  (ka  *ecdheKeyAgreement ) generateServerKeyExchange config  *Config , cert  *Certificate , clientHello  *clientHelloMsg , hello  *serverHelloMsg ) (*serverKeyExchangeMsg , error ) {	var  curveID  CurveID 	for  _ , c  := range  clientHello .supportedCurves  {		if  config .supportsCurve (ka .version , c ) {			curveID  = c 			break 		}	}	if  curveID  == 0  {		return  nil , errors .New ("tls: no supported elliptic curves offered" )	}	if  _ , ok  := curveForCurveID (curveID ); !ok  {		return  nil , errors .New ("tls: CurvePreferences includes unsupported curve" )	}	key , err  := generateECDHEKey (config .rand (), curveID )	if  err  != nil  {		return  nil , err 	}	ka .key  = key 		ecdhePublic  := key .PublicKey ().Bytes ()	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 	}	peerKey , err  := ka .key .Curve ().NewPublicKey (ckx .ciphertext [1 :])	if  err  != nil  {		return  nil , errClientKeyExchange 	}	preMasterSecret , err  := ka .key .ECDH (peerKey )	if  err  != 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 ); !ok  {		return  errors .New ("tls: server selected unsupported curve" )	}	key , err  := generateECDHEKey (config .rand (), curveID )	if  err  != nil  {		return  err 	}	ka .key  = key 	peerKey , err  := key .Curve ().NewPublicKey (publicKey )	if  err  != nil  {		return  errServerKeyExchange 	}	ka .preMasterSecret , err  = key .ECDH (peerKey )	if  err  != nil  {		return  errServerKeyExchange 	}	ourPublicKey  := key .PublicKey ().Bytes ()	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 } The pages are generated with Golds v0.7.6 . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101  (reachable from the left QR code) to get the latest news of Golds .