public static void SendFlightOne3(ref WritableBuffer writer, IConnectionStateTls13 connectionState) { if (connectionState.PskIdentity == -1) { connectionState.WriteHandshake(ref writer, HandshakeType.certificate_verify, SendCertificateVerify); } }
public static void WriteServerName(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian(ExtensionType.server_name); buffer.WriteBigEndian((ushort)(sizeof(ushort) + connectionState.ServerName.Length)); buffer.WriteBigEndian((ushort)connectionState.ServerName.Length); buffer.Write(Encoding.UTF8.GetBytes(connectionState.ServerName)); }
public static WritableBuffer CreateNewSessionKey(WritableBuffer buffer, IConnectionStateTls13 state) { var lifetime = TicketLifeTimeInHours * 60 * 60; buffer.WriteBigEndian((uint)lifetime); buffer.Ensure(4); state.CryptoProvider.FillWithRandom(buffer.Memory.Slice(0, 4)); buffer.Advance(4); BufferExtensions.WriteVector <ushort>(ref buffer, (writer, conn) => { state.ResumptionProvider.GenerateSessionTicket(ref writer, conn); return(writer); }, state); BufferExtensions.WriteVector <ushort>(ref buffer, (writer, conn) => { writer.WriteBigEndian(ExtensionType.ticket_early_data_info); writer.WriteBigEndian <ushort>(sizeof(uint)); uint maxData = 1024 * 2; writer.WriteBigEndian(maxData); return(writer); }, state); return(buffer); }
public static void ReadServerHello(ReadableBuffer readable, IConnectionStateTls13 connectionState) { var original = readable; ushort version, cipherCode; readable = readable.Slice(HandshakeProcessor.HandshakeHeaderSize); readable = readable.SliceBigEndian(out version); //skip random readable = readable.Slice(RandomLength); readable = readable.SliceBigEndian(out cipherCode); connectionState.CipherSuite = connectionState.CryptoProvider.GetCipherSuiteFromCode(cipherCode, connectionState.Version); if (connectionState.CipherSuite == null) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "Could not get a cipher suite during server hello"); } connectionState.StartHandshakeHash(original); readable = BufferExtensions.SliceVector <ushort>(ref readable); ExtensionType ext; readable = readable.SliceBigEndian(out ext); if (ext != ExtensionType.key_share) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "There was no keyshare on the server hello"); } readable = BufferExtensions.SliceVector <ushort>(ref readable); NamedGroup group; readable = readable.SliceBigEndian(out group); if (group != connectionState.KeyShare.NamedGroup) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "The named group didn't match the keyshare during server hello"); } readable = BufferExtensions.SliceVector <ushort>(ref readable); connectionState.KeyShare.SetPeerKey(readable); }
public unsafe KeySchedule(IConnectionStateTls13 state, EphemeralBufferPoolWindows pool, ReadableBuffer resumptionSecret) { _pool = pool; _stateData = pool.Rent(); _state = state; _hashSize = CryptoProvider.HashProvider.HashSize(CipherSuite.HashType); _stateData.Memory.TryGetPointer(out _secret); _clientHandshakeTrafficSecret = ((byte *)_secret) + _hashSize; _serverHandshakeTrafficSecret = _clientHandshakeTrafficSecret + _hashSize; _masterSecret = _serverHandshakeTrafficSecret + _hashSize; _clientApplicationTrafficSecret = _masterSecret + _hashSize; _serverApplicationTrafficSecret = _clientApplicationTrafficSecret + _hashSize; void *resumptionPointer = null; int secretLength = 0; if (resumptionSecret.Length > 0) { var stackSecret = stackalloc byte[resumptionSecret.Length]; resumptionSecret.CopyTo(new Span <byte>(stackSecret, resumptionSecret.Length)); secretLength = resumptionSecret.Length; resumptionPointer = stackSecret; } HkdfFunctions.HkdfExtract(CryptoProvider.HashProvider, CipherSuite.HashType, null, 0, resumptionPointer, secretLength, _secret, _hashSize); }
public static void SendFlightOne(ref WritableBuffer writer, IConnectionStateTls13 connectionState) { connectionState.WriteHandshake(ref writer, HandshakeType.encrypted_extensions, (buffer, state) => { BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, state); return(buffer); }); }
public static void WriteServerEarlyData(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { if (connectionState.EarlyDataSupported) { buffer.WriteBigEndian(ExtensionType.early_data); buffer.WriteBigEndian <ushort>(0); } }
public static void ReadClientHelloTls13(ReadableBuffer readable, IConnectionStateTls13 connectionState) { ReadClientHello(ref readable, connectionState); if (readable.Length == 0) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.protocol_version, "There is no extensions but we need them for Tls 1.3"); } ExtensionsRead.ReadExtensionListTls13(ref readable, connectionState); }
public static void ReadSupportedGroups(ReadableBuffer buffer, IConnectionStateTls13 connectionState) { if (connectionState.KeyShare != null) { return; } buffer = BufferExtensions.SliceVector <ushort>(ref buffer); connectionState.KeyShare = connectionState.CryptoProvider.GetKeyshareFromNamedGroups(buffer); }
public static void WriteSignatureSchemes(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian(ExtensionType.signature_algorithms); BufferExtensions.WriteVector <ushort>(ref buffer, (writer, state) => { connectionState.CryptoProvider.WriteSignatureSchemes(ref writer); return(writer); }, connectionState); }
public static void WriteSupportedGroups(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian(ExtensionType.supported_groups); BufferExtensions.WriteVector <ushort>(ref buffer, (writer, state) => { connectionState.CryptoProvider.WriteSupportedGroups(ref writer); return(writer); }, connectionState); }
public static WritableBuffer SendHelloRetry(WritableBuffer buffer, IConnectionStateTls13 connectionState) { if (connectionState.State == StateType.WaitHelloRetry) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.handshake_failure, "need to send a hello retry but have already sent one"); } buffer.WriteBigEndian(connectionState.Version); BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, connectionState); return(buffer); }
public static void ReadKeyshare(ReadableBuffer buffer, IConnectionStateTls13 connectionState) { if (connectionState.KeyShare?.HasPeerKey == true) { return; } buffer = BufferExtensions.SliceVector <ushort>(ref buffer); var ks = connectionState.CryptoProvider.GetKeyshareFromKeyshare(buffer); connectionState.KeyShare = ks ?? connectionState.KeyShare; }
public static WritableBuffer SendServerHello13(WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.Ensure(RandomLength + sizeof(ushort)); buffer.WriteBigEndian(connectionState.Version); var memoryToFill = buffer.Memory.Slice(0, RandomLength); connectionState.CryptoProvider.FillWithRandom(memoryToFill); buffer.Advance(RandomLength); buffer.WriteBigEndian(connectionState.CipherSuite.CipherCode); BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, connectionState); return(buffer); }
public static void WriteHandshake(this IConnectionStateTls13 state, ref WritableBuffer writer, HandshakeType handshakeType, Func <WritableBuffer, IConnectionStateTls13, WritableBuffer> contentWriter) { var dataWritten = writer.BytesWritten; writer.WriteBigEndian(handshakeType); BufferExtensions.WriteVector24Bit(ref writer, contentWriter, state); if (state.HandshakeHash != null) { var hashBuffer = writer.AsReadableBuffer().Slice(dataWritten); state.HandshakeHash.HashData(hashBuffer); } }
public void DecryptSession(ref ReadableBuffer buffer, IConnectionStateTls13 state) { var nounce = buffer.Slice(0, 12).ToArray(); buffer = buffer.Slice(12); ushort cipherCode, version; buffer = buffer.SliceBigEndian(out cipherCode); buffer = buffer.SliceBigEndian(out version); state.CipherSuite = state.CryptoProvider.GetCipherSuiteFromCode(cipherCode, state.Version); state.KeySchedule = new KeySchedule13(state, state.Listener.KeyScheduleProvider.BufferPool, buffer); }
public static void WriteClientKeyshares(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian(ExtensionType.key_share); BufferExtensions.WriteVector <ushort>(ref buffer, (innerWriter, innerState) => { BufferExtensions.WriteVector <ushort>(ref innerWriter, (writer, state) => { WriteKeyShare(ref writer, state.KeyShare); return(writer); }, innerState); return(innerWriter); }, connectionState); }
public static WritableBuffer WriteCertificate(WritableBuffer writer, IConnectionStateTls13 connectionState) { writer.WriteBigEndian <byte>(0); BufferExtensions.WriteVector24Bit(ref writer, (buffer, state) => { WriteCertificateEntry(ref buffer, state.Certificate.CertificateData); for (int i = 0; i < state.Certificate.CertificateChain.Length; i++) { WriteCertificateEntry(ref buffer, state.Certificate.CertificateChain[i]); } return(buffer); }, connectionState); return(writer); }
public static WritableBuffer WriteClientHello(WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian <ushort>(0x0303); buffer.Ensure(RandomLength); connectionState.CryptoProvider.FillWithRandom(buffer.Memory.Slice(0, RandomLength)); buffer.Advance(RandomLength); //legacy sessionid buffer.WriteBigEndian((byte)0); connectionState.CryptoProvider.WriteCipherSuites(ref buffer); //legacy compression buffer.WriteBigEndian((byte)1); buffer.WriteBigEndian((byte)0); connectionState.KeyShare = connectionState.CryptoProvider.GetDefaultKeyShare(); BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, connectionState); return(buffer); }
public static void ReadPskKeyExchangeMode(ReadableBuffer buffer, IConnectionStateTls13 connectionState) { buffer = BufferExtensions.SliceVector <byte>(ref buffer); while (buffer.Length > 0) { PskKeyExchangeMode mode; buffer = buffer.SliceBigEndian(out mode); if (connectionState.PskKeyExchangeMode == PskKeyExchangeMode.none) { connectionState.PskKeyExchangeMode = mode; } else { connectionState.PskKeyExchangeMode |= mode; } } }
public static unsafe void ServerFinished(ref WritableBuffer writer, IConnectionStateTls13 connectionState, byte[] finishedKey) { var hash = new byte[connectionState.HandshakeHash.HashSize]; fixed(byte *hPtr = hash) fixed(byte *kPtr = finishedKey) { connectionState.HandshakeHash.InterimHash(hPtr, hash.Length); connectionState.CryptoProvider.HashProvider.HmacData(connectionState.CipherSuite.HashType, kPtr, finishedKey.Length, hPtr, hash.Length, hPtr, hash.Length); } connectionState.WriteHandshake(ref writer, HandshakeType.finished, (buffer, state) => { buffer.Write(hash); return(buffer); }); }
public bool TryToResume(long serviceId, long keyId, ReadableBuffer identity, IConnectionStateTls13 state) { for (int i = 0; i < _keyset.Length; i++) { var key = _keyset[i]; if (key == null) { continue; } if (key.ServiceId != serviceId || key.KeyId != keyId) { continue; } state.PskIdentity = 0; key.DecryptSession(ref identity, state); return(true); } return(false); }
public static void ReadPskKey(ReadableBuffer pskBuffer, IConnectionStateTls13 connectionState) { var identities = BufferExtensions.SliceVector <ushort>(ref pskBuffer); while (identities.Length > 0) { var identity = BufferExtensions.SliceVector <ushort>(ref identities); long serviceId, keyId; identity = identity.SliceBigEndian(out serviceId); identity = identity.SliceBigEndian(out keyId); int ticketAge; identities = identities.SliceBigEndian(out ticketAge); if (!connectionState.ResumptionProvider.TryToResume(serviceId, keyId, identity, connectionState)) { continue; } if ((connectionState.PskKeyExchangeMode & PskKeyExchangeMode.psk_dhe_ke) == 0) { connectionState.KeyShare?.Dispose(); connectionState.KeyShare = null; } return; } }
public KeySchedule GetKeySchedule(IConnectionStateTls13 state) { return(new KeySchedule(state, _bufferPool, default(ReadableBuffer))); }
public static void WriteRetryKeyshare(ref WritableBuffer buffer, IConnectionStateTls13 connectionState) { buffer.WriteBigEndian(ExtensionType.key_share); buffer.WriteBigEndian((ushort)sizeof(NamedGroup)); buffer.WriteBigEndian(connectionState.KeyShare.NamedGroup); }
private static void ReadEarlyData(ReadableBuffer earlyData, IConnectionStateTls13 connectionState) { connectionState.EarlyDataSupported = true; }
public static void ReadExtensionListTls13(ref ReadableBuffer buffer, IConnectionStateTls13 connectionState) { ReadableBuffer signatureAlgoBuffer = default(ReadableBuffer); ReadableBuffer pskBuffer = default(ReadableBuffer); if (buffer.Length < sizeof(ushort)) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, $"Extension list is not at least the size of a ushort"); } var listLength = buffer.ReadBigEndian <ushort>(); buffer = buffer.Slice(sizeof(ushort)); if (buffer.Length < listLength) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, "The extension list is not as long as the header says"); } var currentbuffer = buffer.Slice(0, listLength); buffer = buffer.Slice(currentbuffer.End); while (currentbuffer.Length > 3) { var extensionType = currentbuffer.ReadBigEndian <ExtensionType>(); var extensionLength = currentbuffer.Slice(sizeof(ExtensionType)).ReadBigEndian <ushort>(); currentbuffer = currentbuffer.Slice(sizeof(ExtensionType) + sizeof(ushort)); if (currentbuffer.Length < extensionLength) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, $"The extension of type {extensionType} is too long for the remaining buffer"); } var extensionBuffer = currentbuffer.Slice(0, extensionLength); currentbuffer = currentbuffer.Slice(extensionLength); switch (extensionType) { case ExtensionType.server_name: ReadServerName(extensionBuffer, connectionState); break; case ExtensionType.key_share: ReadKeyshare(extensionBuffer, connectionState); break; case ExtensionType.supported_groups: ReadSupportedGroups(extensionBuffer, connectionState); break; case ExtensionType.signature_algorithms: signatureAlgoBuffer = extensionBuffer; break; case ExtensionType.application_layer_protocol_negotiation: ReadApplicationProtocolExtension(extensionBuffer, connectionState); break; case ExtensionType.pre_shared_key: pskBuffer = extensionBuffer; break; case ExtensionType.psk_key_exchange_modes: ReadPskKeyExchangeMode(extensionBuffer, connectionState); break; case ExtensionType.certificate_authorities: break; case ExtensionType.early_data: ReadEarlyData(extensionBuffer, connectionState); break; } } //Wait until the end to check the signature, here we select the //certificate and this could depend on the server name indication //as well as the trusted CA roots. if (signatureAlgoBuffer.Length != 0) { ReadSignatureScheme(signatureAlgoBuffer, connectionState); } //We only check if we want to use a PSK at the end because we need the //entire state (ciphers okay, and all the other information is correct //before we bother if (pskBuffer.Length != 0) { ReadPskKey(pskBuffer, connectionState); } if (currentbuffer.Length != 0) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, "there was data after the extension list which is invalid"); } }
public static void WriteVector24Bit(ref WritableBuffer buffer, Func <WritableBuffer, IConnectionStateTls13, WritableBuffer> writeContent, IConnectionStateTls13 state) { buffer.Ensure(3); var bookmark = buffer.Memory; buffer.Advance(3); int currentSize = buffer.BytesWritten; buffer = writeContent(buffer, state); currentSize = buffer.BytesWritten - currentSize; bookmark.Write24BitNumber(currentSize); }
public unsafe static WritableBuffer SendCertificateVerify(WritableBuffer writer, IConnectionStateTls13 state) { writer.WriteBigEndian(state.SignatureScheme); var bookMark = writer.Memory; writer.WriteBigEndian((ushort)0); var hash = new byte[state.HandshakeHash.HashSize + Tls1_3Consts.SignatureDigestPrefix.Length + Tls1_3Consts.ServerCertificateVerify.Length]; Tls1_3Consts.SignatureDigestPrefix.CopyTo(hash, 0); Tls1_3Consts.ServerCertificateVerify.CopyTo(hash, Tls1_3Consts.SignatureDigestPrefix.Length); fixed(byte *hPtr = hash) { var sigPtr = hPtr + Tls1_3Consts.SignatureDigestPrefix.Length + Tls1_3Consts.ServerCertificateVerify.Length; state.HandshakeHash.InterimHash(sigPtr, state.HandshakeHash.HashSize); var sigSize = state.Certificate.SignHash(state.CryptoProvider.HashProvider, state.SignatureScheme, ref writer, hPtr, hash.Length); bookMark.Span.Write16BitNumber((ushort)sigSize); } return(writer); }
public KeySchedule GetKeySchedule(IConnectionStateTls13 state, ReadableBuffer resumptionSecret) { return(new KeySchedule(state, _bufferPool, resumptionSecret)); }