func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, os.Error) { preMasterSecret := make([]byte, 48) _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) if err != nil { return nil, err } if len(ckx.ciphertext) < 2 { return nil, os.NewError("bad ClientKeyExchange") } ciphertext := ckx.ciphertext if version != versionSSL30 { ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) if ciphertextLen != len(ckx.ciphertext)-2 { return nil, os.NewError("bad ClientKeyExchange") } ciphertext = ckx.ciphertext[2:] } err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret) if err != nil { return nil, err } // We don't check the version number in the premaster secret. For one, // by checking it, we would leak information about the validity of the // encrypted pre-master secret. Secondly, it provides only a small // benefit against a downgrade attack and some implementations send the // wrong version anyway. See the discussion at the end of section // 7.4.7.1 of RFC 4346. return preMasterSecret, nil }
// KeyDecrypt decryptes the encrypted key using RSA PKCS1v1.5 func (d RSAPKCS15KeyDecrypt) KeyDecrypt(enckey []byte) ([]byte, error) { if debug.Enabled { debug.Printf("START PKCS.KeyDecrypt") } // Hey, these notes and workarounds were stolen from go-jose defer func() { // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload // because of an index out of bounds error, which we want to ignore. // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() // only exists for preventing crashes with unpatched versions. // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 _ = recover() }() // Perform some input validation. expectedlen := d.privkey.PublicKey.N.BitLen() / 8 if expectedlen != len(enckey) { // Input size is incorrect, the encrypted payload should always match // the size of the public modulus (e.g. using a 2048 bit key will // produce 256 bytes of output). Reject this since it's invalid input. return nil, fmt.Errorf( "input size for key decrypt is incorrect (expected %d, got %d)", expectedlen, len(enckey), ) } var err error bk, err := d.generator.KeyGenerate() if err != nil { return nil, errors.New("failed to generate key") } cek := bk.Bytes() // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing // the Million Message Attack on Cryptographic Message Syntax". We are // therefore deliberatly ignoring errors here. err = rsa.DecryptPKCS1v15SessionKey(rand.Reader, d.privkey, enckey, cek) if err != nil { return nil, err } return cek, nil }
// Decrypt the given payload. Based on the key encryption algorithm, // this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256). func (ctx rsaDecrypterSigner) decrypt(jek []byte, alg KeyAlgorithm, generator keyGenerator) ([]byte, error) { // Note: The random reader on decrypt operations is only used for blinding, // so stubbing is meanlingless (hence the direct use of rand.Reader). switch alg { case RSA1_5: defer func() { // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload // because of an index out of bounds error, which we want to ignore. // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() // only exists for preventing crashes with unpatched versions. // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 _ = recover() }() // Perform some input validation. keyBytes := ctx.privateKey.PublicKey.N.BitLen() / 8 if keyBytes != len(jek) { // Input size is incorrect, the encrypted payload should always match // the size of the public modulus (e.g. using a 2048 bit key will // produce 256 bytes of output). Reject this since it's invalid input. return nil, ErrCryptoFailure } cek, _, err := generator.genKey() if err != nil { return nil, ErrCryptoFailure } // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing // the Million Message Attack on Cryptographic Message Syntax". We are // therefore deliberately ignoring errors here. _ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, ctx.privateKey, jek, cek) return cek, nil case RSA_OAEP: // Use rand.Reader for RSA blinding return rsa.DecryptOAEP(sha1.New(), rand.Reader, ctx.privateKey, jek, []byte{}) case RSA_OAEP_256: // Use rand.Reader for RSA blinding return rsa.DecryptOAEP(sha256.New(), rand.Reader, ctx.privateKey, jek, []byte{}) } return nil, ErrUnsupportedAlgorithm }
func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { preMasterSecret := make([]byte, 48) _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) if err != nil { return nil, err } if len(ckx.ciphertext) < 2 { return nil, errClientKeyExchange } ciphertext := ckx.ciphertext if version != VersionSSL30 { ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) if ciphertextLen != len(ckx.ciphertext)-2 { return nil, errClientKeyExchange } ciphertext = ckx.ciphertext[2:] } key := cert.PrivateKey.(*rsa.PrivateKey) if ka.exportKey != nil { key = ka.exportKey } err = rsa.DecryptPKCS1v15SessionKey(config.rand(), key, ciphertext, preMasterSecret) if err != nil { return nil, err } // This check should be done in constant-time, but this is a testing // implementation. See the discussion at the end of section 7.4.7.1 of // RFC 4346. vers := uint16(preMasterSecret[0])<<8 | uint16(preMasterSecret[1]) if ka.clientVersion != vers { return nil, fmt.Errorf("tls: invalid version in RSA premaster (got %04x, wanted %04x)", vers, ka.clientVersion) } return preMasterSecret, nil }
func (h *serverHandshake) loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config) { h.writeChan = writeChan h.controlChan = controlChan h.msgChan = msgChan h.config = config defer close(writeChan) defer close(controlChan) clientHello, ok := h.readHandshakeMsg().(*clientHelloMsg) if !ok { h.error(alertUnexpectedMessage) return } major, minor, ok := mutualVersion(clientHello.major, clientHello.minor) if !ok { h.error(alertProtocolVersion) return } finishedHash := newFinishedHash() finishedHash.Write(clientHello.marshal()) hello := new(serverHelloMsg) // We only support a single ciphersuite so we look for it in the list // of client supported suites. // // TODO(agl): Add additional cipher suites. var suite *cipherSuite for _, id := range clientHello.cipherSuites { for _, supported := range cipherSuites { if supported.id == id { suite = &supported break } } } foundCompression := false // We only support null compression, so check that the client offered it. for _, compression := range clientHello.compressionMethods { if compression == compressionNone { foundCompression = true break } } if suite == nil || !foundCompression { h.error(alertHandshakeFailure) return } hello.major = major hello.minor = minor hello.cipherSuite = suite.id currentTime := uint32(config.Time()) hello.random = make([]byte, 32) hello.random[0] = byte(currentTime >> 24) hello.random[1] = byte(currentTime >> 16) hello.random[2] = byte(currentTime >> 8) hello.random[3] = byte(currentTime) _, err := io.ReadFull(config.Rand, hello.random[4:]) if err != nil { h.error(alertInternalError) return } hello.compressionMethod = compressionNone if clientHello.nextProtoNeg { hello.nextProtoNeg = true hello.nextProtos = config.NextProtos } finishedHash.Write(hello.marshal()) writeChan <- writerSetVersion{major, minor} writeChan <- hello if len(config.Certificates) == 0 { h.error(alertInternalError) return } certMsg := new(certificateMsg) certMsg.certificates = config.Certificates[0].Certificate finishedHash.Write(certMsg.marshal()) writeChan <- certMsg helloDone := new(serverHelloDoneMsg) finishedHash.Write(helloDone.marshal()) writeChan <- helloDone ckx, ok := h.readHandshakeMsg().(*clientKeyExchangeMsg) if !ok { h.error(alertUnexpectedMessage) return } finishedHash.Write(ckx.marshal()) preMasterSecret := make([]byte, 48) _, err = io.ReadFull(config.Rand, preMasterSecret[2:]) if err != nil { h.error(alertInternalError) return } err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret) if err != nil { h.error(alertHandshakeFailure) return } // We don't check the version number in the premaster secret. For one, // by checking it, we would leak information about the validity of the // encrypted pre-master secret. Secondly, it provides only a small // benefit against a downgrade attack and some implementations send the // wrong version anyway. See the discussion at the end of section // 7.4.7.1 of RFC 4346. masterSecret, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength) _, ok = h.readHandshakeMsg().(changeCipherSpec) if !ok { h.error(alertUnexpectedMessage) return } cipher, _ := rc4.NewCipher(clientKey) controlChan <- &newCipherSpec{cipher, hmac.New(sha1.New(), clientMAC)} clientProtocol := "" if hello.nextProtoNeg { nextProto, ok := h.readHandshakeMsg().(*nextProtoMsg) if !ok { h.error(alertUnexpectedMessage) return } finishedHash.Write(nextProto.marshal()) clientProtocol = nextProto.proto } clientFinished, ok := h.readHandshakeMsg().(*finishedMsg) if !ok { h.error(alertUnexpectedMessage) return } verify := finishedHash.clientSum(masterSecret) if len(verify) != len(clientFinished.verifyData) || subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { h.error(alertHandshakeFailure) return } controlChan <- ConnectionState{true, "TLS_RSA_WITH_RC4_128_SHA", 0, clientProtocol} finishedHash.Write(clientFinished.marshal()) cipher2, _ := rc4.NewCipher(serverKey) writeChan <- writerChangeCipherSpec{cipher2, hmac.New(sha1.New(), serverMAC)} finished := new(finishedMsg) finished.verifyData = finishedHash.serverSum(masterSecret) writeChan <- finished writeChan <- writerEnableApplicationData{} for { _, ok := h.readHandshakeMsg().(*clientHelloMsg) if !ok { h.error(alertUnexpectedMessage) return } // We reject all renegotication requests. writeChan <- alert{alertLevelWarning, alertNoRenegotiation} } }
func (c *Conn) serverHandshake() os.Error { config := c.config msg, err := c.readHandshake() if err != nil { return err } clientHello, ok := msg.(*clientHelloMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } vers, ok := mutualVersion(clientHello.vers) if !ok { return c.sendAlert(alertProtocolVersion) } c.vers = vers c.haveVers = true finishedHash := newFinishedHash() finishedHash.Write(clientHello.marshal()) hello := new(serverHelloMsg) // We only support a single ciphersuite so we look for it in the list // of client supported suites. // // TODO(agl): Add additional cipher suites. var suite *cipherSuite for _, id := range clientHello.cipherSuites { for _, supported := range cipherSuites { if supported.id == id { suite = &supported break } } } foundCompression := false // We only support null compression, so check that the client offered it. for _, compression := range clientHello.compressionMethods { if compression == compressionNone { foundCompression = true break } } if suite == nil || !foundCompression { return c.sendAlert(alertHandshakeFailure) } hello.vers = vers hello.cipherSuite = suite.id t := uint32(config.Time()) hello.random = make([]byte, 32) hello.random[0] = byte(t >> 24) hello.random[1] = byte(t >> 16) hello.random[2] = byte(t >> 8) hello.random[3] = byte(t) _, err = io.ReadFull(config.Rand, hello.random[4:]) if err != nil { return c.sendAlert(alertInternalError) } hello.compressionMethod = compressionNone if clientHello.nextProtoNeg { hello.nextProtoNeg = true hello.nextProtos = config.NextProtos } finishedHash.Write(hello.marshal()) c.writeRecord(recordTypeHandshake, hello.marshal()) if len(config.Certificates) == 0 { return c.sendAlert(alertInternalError) } certMsg := new(certificateMsg) certMsg.certificates = config.Certificates[0].Certificate finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) if config.AuthenticateClient { // Request a client certificate certReq := new(certificateRequestMsg) certReq.certificateTypes = []byte{certTypeRSASign} // An empty list of certificateAuthorities signals to // the client that it may send any certificate in response // to our request. finishedHash.Write(certReq.marshal()) c.writeRecord(recordTypeHandshake, certReq.marshal()) } helloDone := new(serverHelloDoneMsg) finishedHash.Write(helloDone.marshal()) c.writeRecord(recordTypeHandshake, helloDone.marshal()) var pub *rsa.PublicKey if config.AuthenticateClient { // Get client certificate msg, err = c.readHandshake() if err != nil { return err } certMsg, ok = msg.(*certificateMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(certMsg.marshal()) certs := make([]*x509.Certificate, len(certMsg.certificates)) for i, asn1Data := range certMsg.certificates { cert, err := x509.ParseCertificate(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) return os.ErrorString("could not parse client's certificate: " + err.String()) } certs[i] = cert } // TODO(agl): do better validation of certs: max path length, name restrictions etc. for i := 1; i < len(certs); i++ { if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil { c.sendAlert(alertBadCertificate) return os.ErrorString("could not validate certificate signature: " + err.String()) } } if len(certs) > 0 { key, ok := certs[0].PublicKey.(*rsa.PublicKey) if !ok { return c.sendAlert(alertUnsupportedCertificate) } pub = key c.peerCertificates = certs } } // Get client key exchange msg, err = c.readHandshake() if err != nil { return err } ckx, ok := msg.(*clientKeyExchangeMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(ckx.marshal()) // If we received a client cert in response to our certificate request message, // the client will send us a certificateVerifyMsg immediately after the // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding // handshake-layer messages that is signed using the private key corresponding // to the client's certificate. This allows us to verify that the client is in // posession of the private key of the certificate. if len(c.peerCertificates) > 0 { msg, err = c.readHandshake() if err != nil { return err } certVerify, ok := msg.(*certificateVerifyMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } digest := make([]byte, 36) copy(digest[0:16], finishedHash.serverMD5.Sum()) copy(digest[16:36], finishedHash.serverSHA1.Sum()) err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature) if err != nil { c.sendAlert(alertBadCertificate) return os.ErrorString("could not validate signature of connection nonces: " + err.String()) } finishedHash.Write(certVerify.marshal()) } preMasterSecret := make([]byte, 48) _, err = io.ReadFull(config.Rand, preMasterSecret[2:]) if err != nil { return c.sendAlert(alertInternalError) } err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret) if err != nil { return c.sendAlert(alertHandshakeFailure) } // We don't check the version number in the premaster secret. For one, // by checking it, we would leak information about the validity of the // encrypted pre-master secret. Secondly, it provides only a small // benefit against a downgrade attack and some implementations send the // wrong version anyway. See the discussion at the end of section // 7.4.7.1 of RFC 4346. masterSecret, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength) cipher, _ := rc4.NewCipher(clientKey) c.in.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC)) c.readRecord(recordTypeChangeCipherSpec) if err := c.error(); err != nil { return err } if hello.nextProtoNeg { msg, err = c.readHandshake() if err != nil { return err } nextProto, ok := msg.(*nextProtoMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(nextProto.marshal()) c.clientProtocol = nextProto.proto } msg, err = c.readHandshake() if err != nil { return err } clientFinished, ok := msg.(*finishedMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } verify := finishedHash.clientSum(masterSecret) if len(verify) != len(clientFinished.verifyData) || subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { return c.sendAlert(alertHandshakeFailure) } finishedHash.Write(clientFinished.marshal()) cipher2, _ := rc4.NewCipher(serverKey) c.out.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC)) c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) finished := new(finishedMsg) finished.verifyData = finishedHash.serverSum(masterSecret) c.writeRecord(recordTypeHandshake, finished.marshal()) c.handshakeComplete = true c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA return nil }
func (c *Conn) serverHandshake() os.Error { config := c.config msg, err := c.readHandshake() if err != nil { return err } clientHello, ok := msg.(*clientHelloMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } vers, ok := mutualVersion(clientHello.vers) if !ok { return c.sendAlert(alertProtocolVersion) } c.vers = vers c.haveVers = true finishedHash := newFinishedHash() finishedHash.Write(clientHello.marshal()) hello := new(serverHelloMsg) // We only support a single ciphersuite so we look for it in the list // of client supported suites. // // TODO(agl): Add additional cipher suites. var suite *cipherSuite for _, id := range clientHello.cipherSuites { for _, supported := range cipherSuites { if supported.id == id { suite = &supported break } } } foundCompression := false // We only support null compression, so check that the client offered it. for _, compression := range clientHello.compressionMethods { if compression == compressionNone { foundCompression = true break } } if suite == nil || !foundCompression { return c.sendAlert(alertHandshakeFailure) } hello.vers = vers hello.cipherSuite = suite.id t := uint32(config.Time()) hello.random = make([]byte, 32) hello.random[0] = byte(t >> 24) hello.random[1] = byte(t >> 16) hello.random[2] = byte(t >> 8) hello.random[3] = byte(t) _, err = io.ReadFull(config.Rand, hello.random[4:]) if err != nil { return c.sendAlert(alertInternalError) } hello.compressionMethod = compressionNone if clientHello.nextProtoNeg { hello.nextProtoNeg = true hello.nextProtos = config.NextProtos } finishedHash.Write(hello.marshal()) c.writeRecord(recordTypeHandshake, hello.marshal()) if len(config.Certificates) == 0 { return c.sendAlert(alertInternalError) } certMsg := new(certificateMsg) certMsg.certificates = config.Certificates[0].Certificate finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) helloDone := new(serverHelloDoneMsg) finishedHash.Write(helloDone.marshal()) c.writeRecord(recordTypeHandshake, helloDone.marshal()) msg, err = c.readHandshake() if err != nil { return err } ckx, ok := msg.(*clientKeyExchangeMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(ckx.marshal()) preMasterSecret := make([]byte, 48) _, err = io.ReadFull(config.Rand, preMasterSecret[2:]) if err != nil { return c.sendAlert(alertInternalError) } err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret) if err != nil { return c.sendAlert(alertHandshakeFailure) } // We don't check the version number in the premaster secret. For one, // by checking it, we would leak information about the validity of the // encrypted pre-master secret. Secondly, it provides only a small // benefit against a downgrade attack and some implementations send the // wrong version anyway. See the discussion at the end of section // 7.4.7.1 of RFC 4346. masterSecret, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength) cipher, _ := rc4.NewCipher(clientKey) c.in.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC)) c.readRecord(recordTypeChangeCipherSpec) if err := c.error(); err != nil { return err } if hello.nextProtoNeg { msg, err = c.readHandshake() if err != nil { return err } nextProto, ok := msg.(*nextProtoMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(nextProto.marshal()) c.clientProtocol = nextProto.proto } msg, err = c.readHandshake() if err != nil { return err } clientFinished, ok := msg.(*finishedMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } verify := finishedHash.clientSum(masterSecret) if len(verify) != len(clientFinished.verifyData) || subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { return c.sendAlert(alertHandshakeFailure) } finishedHash.Write(clientFinished.marshal()) cipher2, _ := rc4.NewCipher(serverKey) c.out.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC)) c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) finished := new(finishedMsg) finished.verifyData = finishedHash.serverSum(masterSecret) c.writeRecord(recordTypeHandshake, finished.marshal()) c.handshakeComplete = true c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA return nil }