Skip to content

Commit

Permalink
extract std.crypto.tls.Client into separate namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Dec 16, 2022
1 parent 68e289f commit d17314c
Show file tree
Hide file tree
Showing 4 changed files with 385 additions and 368 deletions.
2 changes: 1 addition & 1 deletion lib/std/crypto.zig
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ const std = @import("std.zig");

pub const errors = @import("crypto/errors.zig");

pub const Tls = @import("crypto/Tls.zig");
pub const tls = @import("crypto/tls.zig");

test {
_ = aead.aegis.Aegis128L;
Expand Down
325 changes: 325 additions & 0 deletions lib/std/crypto/tls.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
//! Plaintext:
//! * type: ContentType
//! * legacy_record_version: u16 = 0x0303,
//! * length: u16,
//! - The length (in bytes) of the following TLSPlaintext.fragment. The
//! length MUST NOT exceed 2^14 bytes.
//! * fragment: opaque
//! - the data being transmitted
//!
//! Ciphertext
//! * ContentType opaque_type = application_data; /* 23 */
//! * ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
//! * uint16 length;
//! * opaque encrypted_record[TLSCiphertext.length];
//!
//! Handshake:
//! * type: HandshakeType
//! * length: u24
//! * data: opaque
//!
//! ServerHello:
//! * ProtocolVersion legacy_version = 0x0303;
//! * Random random;
//! * opaque legacy_session_id_echo<0..32>;
//! * CipherSuite cipher_suite;
//! * uint8 legacy_compression_method = 0;
//! * Extension extensions<6..2^16-1>;
//!
//! Extension:
//! * ExtensionType extension_type;
//! * opaque extension_data<0..2^16-1>;

const std = @import("../std.zig");
const Tls = @This();
const net = std.net;
const mem = std.mem;
const crypto = std.crypto;
const assert = std.debug.assert;

pub const Client = @import("tls/Client.zig");

pub const ciphertext_record_header_len = 5;
pub const max_ciphertext_len = (1 << 14) + 256;
pub const max_ciphertext_record_len = max_ciphertext_len + ciphertext_record_header_len;
pub const hello_retry_request_sequence = [32]u8{
0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
};

pub const ProtocolVersion = enum(u16) {
tls_1_2 = 0x0303,
tls_1_3 = 0x0304,
_,
};

pub const ContentType = enum(u8) {
invalid = 0,
change_cipher_spec = 20,
alert = 21,
handshake = 22,
application_data = 23,
_,
};

pub const HandshakeType = enum(u8) {
client_hello = 1,
server_hello = 2,
new_session_ticket = 4,
end_of_early_data = 5,
encrypted_extensions = 8,
certificate = 11,
certificate_request = 13,
certificate_verify = 15,
finished = 20,
key_update = 24,
message_hash = 254,
};

pub const ExtensionType = enum(u16) {
/// RFC 6066
server_name = 0,
/// RFC 6066
max_fragment_length = 1,
/// RFC 6066
status_request = 5,
/// RFC 8422, 7919
supported_groups = 10,
/// RFC 8446
signature_algorithms = 13,
/// RFC 5764
use_srtp = 14,
/// RFC 6520
heartbeat = 15,
/// RFC 7301
application_layer_protocol_negotiation = 16,
/// RFC 6962
signed_certificate_timestamp = 18,
/// RFC 7250
client_certificate_type = 19,
/// RFC 7250
server_certificate_type = 20,
/// RFC 7685
padding = 21,
/// RFC 8446
pre_shared_key = 41,
/// RFC 8446
early_data = 42,
/// RFC 8446
supported_versions = 43,
/// RFC 8446
cookie = 44,
/// RFC 8446
psk_key_exchange_modes = 45,
/// RFC 8446
certificate_authorities = 47,
/// RFC 8446
oid_filters = 48,
/// RFC 8446
post_handshake_auth = 49,
/// RFC 8446
signature_algorithms_cert = 50,
/// RFC 8446
key_share = 51,
};

pub const AlertLevel = enum(u8) {
warning = 1,
fatal = 2,
_,
};

pub const AlertDescription = enum(u8) {
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,
record_overflow = 22,
handshake_failure = 40,
bad_certificate = 42,
unsupported_certificate = 43,
certificate_revoked = 44,
certificate_expired = 45,
certificate_unknown = 46,
illegal_parameter = 47,
unknown_ca = 48,
access_denied = 49,
decode_error = 50,
decrypt_error = 51,
protocol_version = 70,
insufficient_security = 71,
internal_error = 80,
inappropriate_fallback = 86,
user_canceled = 90,
missing_extension = 109,
unsupported_extension = 110,
unrecognized_name = 112,
bad_certificate_status_response = 113,
unknown_psk_identity = 115,
certificate_required = 116,
no_application_protocol = 120,
_,
};

pub const SignatureScheme = enum(u16) {
// RSASSA-PKCS1-v1_5 algorithms
rsa_pkcs1_sha256 = 0x0401,
rsa_pkcs1_sha384 = 0x0501,
rsa_pkcs1_sha512 = 0x0601,

// ECDSA algorithms
ecdsa_secp256r1_sha256 = 0x0403,
ecdsa_secp384r1_sha384 = 0x0503,
ecdsa_secp521r1_sha512 = 0x0603,

// RSASSA-PSS algorithms with public key OID rsaEncryption
rsa_pss_rsae_sha256 = 0x0804,
rsa_pss_rsae_sha384 = 0x0805,
rsa_pss_rsae_sha512 = 0x0806,

// EdDSA algorithms
ed25519 = 0x0807,
ed448 = 0x0808,

// RSASSA-PSS algorithms with public key OID RSASSA-PSS
rsa_pss_pss_sha256 = 0x0809,
rsa_pss_pss_sha384 = 0x080a,
rsa_pss_pss_sha512 = 0x080b,

// Legacy algorithms
rsa_pkcs1_sha1 = 0x0201,
ecdsa_sha1 = 0x0203,

_,
};

pub const NamedGroup = enum(u16) {
// Elliptic Curve Groups (ECDHE)
secp256r1 = 0x0017,
secp384r1 = 0x0018,
secp521r1 = 0x0019,
x25519 = 0x001D,
x448 = 0x001E,

// Finite Field Groups (DHE)
ffdhe2048 = 0x0100,
ffdhe3072 = 0x0101,
ffdhe4096 = 0x0102,
ffdhe6144 = 0x0103,
ffdhe8192 = 0x0104,

_,
};

pub const CipherSuite = enum(u16) {
TLS_AES_128_GCM_SHA256 = 0x1301,
TLS_AES_256_GCM_SHA384 = 0x1302,
TLS_CHACHA20_POLY1305_SHA256 = 0x1303,
TLS_AES_128_CCM_SHA256 = 0x1304,
TLS_AES_128_CCM_8_SHA256 = 0x1305,
};

pub const CipherParams = union(CipherSuite) {
TLS_AES_128_GCM_SHA256: struct {
pub const AEAD = crypto.aead.aes_gcm.Aes128Gcm;
pub const Hash = crypto.hash.sha2.Sha256;
pub const Hmac = crypto.auth.hmac.Hmac(Hash);
pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);

handshake_secret: [Hkdf.key_len]u8,
master_secret: [Hkdf.key_len]u8,
client_handshake_key: [AEAD.key_length]u8,
server_handshake_key: [AEAD.key_length]u8,
client_finished_key: [Hmac.key_length]u8,
server_finished_key: [Hmac.key_length]u8,
client_handshake_iv: [AEAD.nonce_length]u8,
server_handshake_iv: [AEAD.nonce_length]u8,
transcript_hash: Hash,
},
TLS_AES_256_GCM_SHA384: struct {
pub const AEAD = crypto.aead.aes_gcm.Aes256Gcm;
pub const Hash = crypto.hash.sha2.Sha384;
pub const Hmac = crypto.auth.hmac.Hmac(Hash);
pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);

handshake_secret: [Hkdf.key_len]u8,
master_secret: [Hkdf.key_len]u8,
client_handshake_key: [AEAD.key_length]u8,
server_handshake_key: [AEAD.key_length]u8,
client_finished_key: [Hmac.key_length]u8,
server_finished_key: [Hmac.key_length]u8,
client_handshake_iv: [AEAD.nonce_length]u8,
server_handshake_iv: [AEAD.nonce_length]u8,
transcript_hash: Hash,
},
TLS_CHACHA20_POLY1305_SHA256: void,
TLS_AES_128_CCM_SHA256: void,
TLS_AES_128_CCM_8_SHA256: void,
};

/// Encryption parameters for application traffic.
pub const ApplicationCipher = union(CipherSuite) {
TLS_AES_128_GCM_SHA256: struct {
pub const AEAD = crypto.aead.aes_gcm.Aes128Gcm;
pub const Hash = crypto.hash.sha2.Sha256;
pub const Hmac = crypto.auth.hmac.Hmac(Hash);
pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);

client_key: [AEAD.key_length]u8,
server_key: [AEAD.key_length]u8,
client_iv: [AEAD.nonce_length]u8,
server_iv: [AEAD.nonce_length]u8,
},
TLS_AES_256_GCM_SHA384: struct {
pub const AEAD = crypto.aead.aes_gcm.Aes256Gcm;
pub const Hash = crypto.hash.sha2.Sha384;
pub const Hmac = crypto.auth.hmac.Hmac(Hash);
pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);

client_key: [AEAD.key_length]u8,
server_key: [AEAD.key_length]u8,
client_iv: [AEAD.nonce_length]u8,
server_iv: [AEAD.nonce_length]u8,
},
TLS_CHACHA20_POLY1305_SHA256: void,
TLS_AES_128_CCM_SHA256: void,
TLS_AES_128_CCM_8_SHA256: void,
};

pub fn hkdfExpandLabel(
comptime Hkdf: type,
key: [Hkdf.key_len]u8,
label: []const u8,
context: []const u8,
comptime len: usize,
) [len]u8 {
const max_label_len = 255;
const max_context_len = 255;
const tls13 = "tls13 ";
var buf: [2 + 1 + tls13.len + max_label_len + 1 + max_context_len]u8 = undefined;
mem.writeIntBig(u16, buf[0..2], len);
buf[2] = @intCast(u8, tls13.len + label.len);
buf[3..][0..tls13.len].* = tls13.*;
var i: usize = 3 + tls13.len;
mem.copy(u8, buf[i..], label);
i += label.len;
buf[i] = @intCast(u8, context.len);
i += 1;
mem.copy(u8, buf[i..], context);
i += context.len;

var result: [len]u8 = undefined;
Hkdf.expand(&result, buf[0..i], key);
return result;
}

pub fn emptyHash(comptime Hash: type) [Hash.digest_length]u8 {
var result: [Hash.digest_length]u8 = undefined;
Hash.hash(&.{}, &result, .{});
return result;
}

pub fn hmac(comptime Hmac: type, message: []const u8, key: [Hmac.key_length]u8) [Hmac.mac_length]u8 {
var result: [Hmac.mac_length]u8 = undefined;
Hmac.create(&result, message, &key);
return result;
}
Loading

0 comments on commit d17314c

Please sign in to comment.