cafe 1.0.1
See the version list below for details.
dotnet add package cafe --version 1.0.1
NuGet\Install-Package cafe -Version 1.0.1
<PackageReference Include="cafe" Version="1.0.1" />
<PackageVersion Include="cafe" Version="1.0.1" />
<PackageReference Include="cafe" />
paket add cafe --version 1.0.1
#r "nuget: cafe, 1.0.1"
#:package cafe@1.0.1
#addin nuget:?package=cafe&version=1.0.1
#tool nuget:?package=cafe&version=1.0.1
BouncyCastle TLS 1.3 Handshake Flow
Based on BouncyCastle C# source (bc-csharp-master/crypto/src/tls/).
State Machine
Key states defined in TlsProtocol.cs:
| State | Value | Description |
|---|---|---|
| CS_START | 0 | Initial, waiting for ClientHello |
| CS_CLIENT_HELLO | 1 | ClientHello received |
| CS_SERVER_HELLO_RETRY_REQUEST | 2 | HelloRetryRequest sent |
| CS_CLIENT_HELLO_RETRY | 3 | Second ClientHello received |
| CS_SERVER_HELLO | 4 | ServerHello sent |
| CS_SERVER_ENCRYPTED_EXTENSIONS | 5 | EncryptedExtensions sent |
| CS_SERVER_CERTIFICATE | 7 | Certificate sent |
| CS_SERVER_FINISHED | 20 | Server Finished sent |
| CS_CLIENT_FINISHED | 18 | Client Finished received |
| CS_END | 21 | Handshake complete |
Full Handshake Sequence (No HelloRetryRequest)
Client Server
| |
| 1. ClientHello |
|------------------------------>| CS_START -> CS_CLIENT_HELLO
| | ReceiveClientHelloMessage()
| | Generate13ServerHello()
| | - Negotiate version/cipher suite
| | - ECDHE key exchange (embedded)
| | - Derive earlySecret, handshakeSecret, masterSecret
| |
| 2. ServerHello |
|<------------------------------| CS_SERVER_HELLO
| | SendServerHelloMessage()
| |
| [ChangeCipherSpec] |
|<------------------------------| Middlebox compatibility (RFC 8446 D.4)
| |
| === Encrypted from here === |
| | Send13ServerHelloCoda()
| | Establish13PhaseHandshake()
| | -> derive "c hs traffic", "s hs traffic"
| | EnablePendingCipherWrite()
| |
| 3. EncryptedExtensions |
|<------------------------------| CS_SERVER_ENCRYPTED_EXTENSIONS
| | Send13EncryptedExtensionsMessage()
| |
| 4. [CertificateRequest] |
|<------------------------------| (optional, client auth)
| |
| 5. Certificate |
|<------------------------------| CS_SERVER_CERTIFICATE
| | Establish13ServerCredentials() -> GetCredentials()
| | Send13CertificateMessage()
| | Certificate.Encode() requires:
| | TLS 1.3: certificateRequestContext = EmptyBytes (not null)
| | TLS 1.2: certificateRequestContext = null
| |
| 6. CertificateVerify |
|<------------------------------| Generate13CertificateVerify()
| | TLS 1.3 only allows RSA-PSS (not PKCS#1 v1.5)
| | SignatureAndHashAlgorithm must use Intrinsic hash
| |
| 7. Finished |
|<------------------------------| CS_SERVER_FINISHED
| | Send13FinishedMessage()
| | Establish13PhaseApplication()
| | -> derive "c ap traffic", "s ap traffic"
| | EnablePendingCipherWrite()
| |
| 8. [Certificate] |
|------------------------------>| (only if CertificateRequest was sent)
| 9. [CertificateVerify] |
|------------------------------>|
| |
| 10. Finished |
|------------------------------>| CS_CLIENT_FINISHED
| | Receive13ClientFinished()
| | Verify client's verify_data
| | EnablePendingCipherRead()
| | CompleteHandshake()
| |
| <==== Application Data ====> | CS_END
Key Exchange (ECDHE)
TLS 1.3 key exchange happens inside Generate13ServerHello(), NOT via the m_keyExchange object:
SelectKeyShareGroup()- negotiate ECDH group from client/server supported groupsFindEarlyKeyShare()- check if client sent a share for the negotiated group- If no match → trigger HelloRetryRequest
- If match → create
TlsAgreement:agreement.ReceivePeerValue(clientShare.KeyExchange)- feed client's public keyagreement.GenerateEphemeral()- generate server ephemeral key pairagreement.CalculateSecret()- compute shared secret
Secret Derivation
Three phases of key derivation via HKDF:
0-RTT: earlySecret = HKDF-Extract(0, PSK_or_0)
|
Handshake: handshakeSecret = HKDF-Extract(derivedSecret, sharedSecret)
|
App: masterSecret = HKDF-Extract(derivedSecret, 0)
Establish13PhaseSecrets()- derives all three phase secretsEstablish13PhaseHandshake()- derives handshake traffic keys from handshakeSecretEstablish13PhaseApplication()- derives application traffic keys from masterSecret
TLS 1.3 vs TLS 1.2 Differences in BouncyCastle
| Aspect | TLS 1.2 | TLS 1.3 |
|---|---|---|
| KeyExchangeAlgorithm | ECDHE_RSA(19), DHE_RSA(5), etc. | NULL(0) |
| Certificate.RequestContext | must be null | must be non-null (EmptyBytes for server) |
| CertificateVerify signature | RSA PKCS#1 v1.5 allowed | RSA-PSS only |
| SignatureAndHashAlgorithm for PSS | GetInstance(sha256, rsa_pss_rsae_sha256) | Use static fields: SignatureAndHashAlgorithm.rsa_pss_rsae_sha256 (hash=Intrinsic) |
| Key exchange object | m_keyExchange | embedded in Generate13ServerHello() |
| Encryption start | after ChangeCipherSpec | after ServerHello (all subsequent messages encrypted) |
Pitfalls Encountered
1. KeyExchangeAlgorithm.NULL (0)
TLS 1.3 cipher suites map to KeyExchangeAlgorithm.NULL = 0. DefaultTlsServer.GetCredentials() doesn't handle this case, throws internal_error. Fix: override GetCredentials() to handle NULL.
2. Certificate.Encode() certificateRequestContext
Certificate constructed via new Certificate(TlsCertificate[]) sets certificateRequestContext = null. TLS 1.3's Encode() asserts it must be non-null. Fix: for TLS 1.3, reconstruct with new Certificate(TlsUtilities.EmptyBytes, entries).
3. RSA-PSS SignatureAndHashAlgorithm
GetInstance(HashAlgorithm.sha256, SignatureAlgorithm.rsa_pss_rsae_sha256) creates a wrong instance (hash=4). The correct instance has hash=8 (Intrinsic). Fix: use SignatureAndHashAlgorithm.rsa_pss_rsae_sha256 static field. TLS 1.3 clients reject PKCS#1 v1.5 in CertificateVerify with illegal_parameter(47).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- BouncyCastle.Cryptography (>= 2.7.0-beta.19)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
初始版本