protected bool VerifySignature(CertificatePublicKey publicKey, byte[] data, byte[] signedParams) { // Initialize the signature position and validity int position = 0; bool signatureOk = false; // Get the corresponding signer for public key SignatureAlgorithm sigAlg = _pluginManager.GetSignatureAlgorithmByOid(publicKey.Oid); if (sigAlg == null) { throw new AlertException(AlertDescription.IllegalParameter, "Signer for given public key not found"); } // Select hash algorithm, null means SSLv3/TLSv1 hash HashAlgorithm hashAlgorithm = null; if (_version.HasSelectableSighash) { byte hashAlgorithmType = signedParams[position++]; byte signAlgorithmType = signedParams[position++]; if (sigAlg.SignatureAlgorithmType != signAlgorithmType) { throw new AlertException(AlertDescription.DecryptError, "Certificate signed with invalid signature algorithm"); } if (!sigAlg.SupportsHashAlgorithmType(hashAlgorithmType)) { throw new AlertException(AlertDescription.DecryptError, "Certificate signed with invalid hash algorithm"); } hashAlgorithm = GetSignatureHashAlgorithm(sigAlg, hashAlgorithmType); } // Check that signature length is valid (same as stored) int len = (signedParams[position] << 8) | signedParams[position + 1]; if (len != signedParams.Length - position - 2) { throw new AlertException(AlertDescription.DecodeError, "Signature length not valid"); } position += 2; // Extract the signature from the end of the signed parameters byte[] signature = new byte[len]; Buffer.BlockCopy(signedParams, position, signature, 0, len); // Verify correctness of the signature signatureOk = sigAlg.VerifyData(_version, data, hashAlgorithm, publicKey, signature); if (!signatureOk) { throw new AlertException(AlertDescription.DecodeError, "Signature from server incorrect"); } return signatureOk; }
protected override void ProcessServerHelloDone(HandshakeMessage serverHelloDone) { if (_state != HandshakeState.ReceivedCertificate && _state != HandshakeState.ReceivedServerKeyExchange && _state != HandshakeState.ReceivedCertificateRequest) { throw new AlertException(AlertDescription.UnexpectedMessage, "Server hello done received at the wrong time"); } bool clientCertificateSent = false; if (_clientCertificateRequested) { // Ask for correct certificate from the callback int certificateIndex = _certificateSelectionCallback(_availableCertificates.ToArray(), _serverCertificates); if (certificateIndex >= 0 && certificateIndex < _availableCertificates.Count) { _clientCertificates.AddRange(_availableCertificates[certificateIndex]); _selectedPrivateKey = _availablePrivateKeys[certificateIndex]; } // If certificate was selected, send it to server if (_clientCertificates.Count > 0) { HandshakeCertificate certificate = new HandshakeCertificate(_version); certificate.CertificateList.AddRange(_clientCertificates); OutputMessage(certificate); clientCertificateSent = true; } else { // TODO: In case of SSLv3 we should send warning alert instead? HandshakeCertificate certificate = new HandshakeCertificate(_version); OutputMessage(certificate); } } // Send client key exchange message byte[] clientKeys = null; if (_serverCertificates.Count > 0) { var cert = _serverCertificates[0]; CertificatePublicKey publicKey = new CertificatePublicKey(cert); this.logger?.Trace($"OID (lookup with http://www.oid-info.com/get/[oid]) of key from server certificate: {publicKey.Oid}"); var data = Asn1Object.FromByteArray(cert.GetKeyAlgorithmParameters()); this.logger?.Trace($" OID of key parameters from server certificate: {data}"); clientKeys = _cipherSuite.KeyExchangeAlgorithm.GetClientKeys(_version, _maxVersion, publicKey); } HandshakeMessage keyex = new HandshakeMessage(HandshakeMessageType.ClientKeyExchange, _version, clientKeys); OutputMessage(keyex); if (clientCertificateSent) { // Get all handshake messages byte[] handshakeMessages = _handshakeStream.ToArray(); // FIXME: Generate the signature of handshakeMessages with client cert signature // this breaks if client certificate signature is different type than negotiated byte[] signature = GenerateSignature(_selectedPrivateKey, handshakeMessages); // Create CertificateVerify message and send it to server HandshakeMessage verify = new HandshakeMessage(HandshakeMessageType.CertificateVerify, _version, signature); OutputMessage(verify); } // Generate the master secret from key exchange _connectionState.MasterSecret = GenerateMasterSecret(_version, _cipherSuite, _connectionState); // Wait for changecipherspec+finished _state = HandshakeState.SendChangeCipherSpec; }
protected override void ProcessCertificateVerify(HandshakeMessage verify) { if (_state != HandshakeState.ReceivedClientKeyExchange) { throw new AlertException(AlertDescription.UnexpectedMessage, "Certificate verify received at the wrong time"); } if (!_clientCertificateReceived) { throw new AlertException(AlertDescription.UnexpectedMessage, "Certificate verify received even though client certificate not received"); } // Get all handshake messages up to, but not including, this one byte[] allMessages = _handshakeStream.ToArray(); byte[] handshakeMessages = new byte[allMessages.Length - verify.Encode().Length]; Buffer.BlockCopy(allMessages, 0, handshakeMessages, 0, handshakeMessages.Length); // Verify the signature of handshake messages CertificatePublicKey publicKey = new CertificatePublicKey(_clientCertificates[0]); bool signatureOk = VerifySignature(publicKey, handshakeMessages, verify.Data); if (!signatureOk) { throw new AlertException(AlertDescription.DecodeError, "Signature from client incorrect"); } // Wait for changecipherspec+finished _state = HandshakeState.ReceivedCertificateVerify; }
protected override void ProcessServerKeyExchange(HandshakeMessage keyExchange) { if (_state != HandshakeState.ReceivedServerHello && _state != HandshakeState.ReceivedCertificate) { throw new AlertException(AlertDescription.UnexpectedMessage, "Server key exchange received at the wrong time"); } if (!_cipherSuite.IsAnonymous && _serverCertificates.Count == 0) { throw new AlertException(AlertDescription.HandshakeFailure, "No certificate received even though cipher suite is not anonymous"); } // Process server keys, also returns us the signature data var cert = _serverCertificates[0]; byte[] signature = _cipherSuite.KeyExchangeAlgorithm.ProcessServerKeys(_version, keyExchange.Data, cert); // Extract the signed data from the complete payload byte[] serverKeys = new byte[keyExchange.Data.Length - signature.Length]; Buffer.BlockCopy(keyExchange.Data, 0, serverKeys, 0, serverKeys.Length); // Verify correctness of the signature if (!_cipherSuite.IsAnonymous) { CertificatePublicKey publicKey = new CertificatePublicKey(cert); // Generate the original data signed from server keys byte[] signedData = new byte[_connectionState.ClientRandom.Length + _connectionState.ServerRandom.Length + serverKeys.Length]; Buffer.BlockCopy(_connectionState.ClientRandom, 0, signedData, 0, _connectionState.ClientRandom.Length); Buffer.BlockCopy(_connectionState.ServerRandom, 0, signedData, _connectionState.ClientRandom.Length, _connectionState.ServerRandom.Length); Buffer.BlockCopy(serverKeys, 0, signedData, _connectionState.ClientRandom.Length + _connectionState.ServerRandom.Length, serverKeys.Length); bool signatureOk = VerifySignature(publicKey, signedData, signature); if (!signatureOk) { throw new AlertException(AlertDescription.DecodeError, "Signature from server incorrect"); } } // Wait for certificate request or server hello done _state = HandshakeState.ReceivedServerKeyExchange; }