authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-18 18:51:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:57:15-07:00
loge2c16d03abae01538ec8ca65e6dc1ecc6f6ec420
tree98ffce6763c2a964a9bff59e2aa649bd18cc29cd
parentf460c2170504ce94471b16631c43638f50735241

std.crypto.tls.Client: support secp256r1 for handshake


1 files changed, 31 insertions(+), 15 deletions(-)

lib/std/crypto/tls/Client.zig+31-15
...@@ -46,7 +46,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -46,7 +46,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
46 // Only possible to happen if the private key is all zeroes.46 // Only possible to happen if the private key is all zeroes.
47 error.IdentityElement => return error.InsufficientEntropy,47 error.IdentityElement => return error.InsufficientEntropy,
48 };48 };
49 _ = secp256r1_kp;
5049
51 const extensions_payload =50 const extensions_payload =
52 tls.extension(.supported_versions, [_]u8{51 tls.extension(.supported_versions, [_]u8{
...@@ -70,11 +69,14 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -70,11 +69,14 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
70 .rsa_pkcs1_sha1,69 .rsa_pkcs1_sha1,
71 .ecdsa_sha1,70 .ecdsa_sha1,
72 })) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{71 })) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{
73 //.secp256r1,72 .secp256r1,
74 .x25519,73 .x25519,
75 })) ++ tls.extension(74 })) ++ tls.extension(
76 .key_share,75 .key_share,
77 array(1, int2(@enumToInt(tls.NamedGroup.x25519)) ++ array(1, x25519_kp.public_key)),76 array(1, int2(@enumToInt(tls.NamedGroup.x25519)) ++
77 array(1, x25519_kp.public_key) ++
78 int2(@enumToInt(tls.NamedGroup.secp256r1)) ++
79 array(1, secp256r1_kp.public_key.toUncompressedSec1())),
78 ) ++80 ) ++
79 int2(@enumToInt(tls.ExtensionType.server_name)) ++81 int2(@enumToInt(tls.ExtensionType.server_name)) ++
80 int2(host_len + 5) ++ // byte length of this extension payload82 int2(host_len + 5) ++ // byte length of this extension payload
...@@ -182,7 +184,8 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -182,7 +184,8 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
182 i += 2;184 i += 2;
183 if (i + extensions_size != frag.len) return error.TlsBadLength;185 if (i + extensions_size != frag.len) return error.TlsBadLength;
184 var supported_version: u16 = 0;186 var supported_version: u16 = 0;
185 var opt_x25519_server_pub_key: ?*[32]u8 = null;187 var shared_key: [32]u8 = undefined;
188 var have_shared_key = false;
186 while (i < frag.len) {189 while (i < frag.len) {
187 const et = mem.readIntBig(u16, frag[i..][0..2]);190 const et = mem.readIntBig(u16, frag[i..][0..2]);
188 i += 2;191 i += 2;
...@@ -196,15 +199,34 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -196,15 +199,34 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
196 supported_version = mem.readIntBig(u16, frag[i..][0..2]);199 supported_version = mem.readIntBig(u16, frag[i..][0..2]);
197 },200 },
198 @enumToInt(tls.ExtensionType.key_share) => {201 @enumToInt(tls.ExtensionType.key_share) => {
199 if (opt_x25519_server_pub_key != null) return error.TlsIllegalParameter;202 if (have_shared_key) return error.TlsIllegalParameter;
203 have_shared_key = true;
200 const named_group = mem.readIntBig(u16, frag[i..][0..2]);204 const named_group = mem.readIntBig(u16, frag[i..][0..2]);
201 i += 2;205 i += 2;
206 const key_size = mem.readIntBig(u16, frag[i..][0..2]);
207 i += 2;
208
202 switch (named_group) {209 switch (named_group) {
203 @enumToInt(tls.NamedGroup.x25519) => {210 @enumToInt(tls.NamedGroup.x25519) => {
204 const key_size = mem.readIntBig(u16, frag[i..][0..2]);
205 i += 2;
206 if (key_size != 32) return error.TlsBadLength;211 if (key_size != 32) return error.TlsBadLength;
207 opt_x25519_server_pub_key = frag[i..][0..32];212 const server_pub_key = frag[i..][0..32];
213
214 shared_key = crypto.dh.X25519.scalarmult(
215 x25519_kp.secret_key,
216 server_pub_key.*,
217 ) catch return error.TlsDecryptFailure;
218 },
219 @enumToInt(tls.NamedGroup.secp256r1) => {
220 const server_pub_key = frag[i..][0..key_size];
221
222 const PublicKey = crypto.sign.ecdsa.EcdsaP256Sha256.PublicKey;
223 const pk = PublicKey.fromSec1(server_pub_key) catch {
224 return error.TlsDecryptFailure;
225 };
226 const mul = pk.p.mulPublic(secp256r1_kp.secret_key.bytes, .Big) catch {
227 return error.TlsDecryptFailure;
228 };
229 shared_key = mul.affineCoordinates().x.toBytes(.Big);
208 },230 },
209 else => {231 else => {
210 std.debug.print("named group: {x}\n", .{named_group});232 std.debug.print("named group: {x}\n", .{named_group});
...@@ -218,8 +240,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -218,8 +240,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
218 }240 }
219 i = next_i;241 i = next_i;
220 }242 }
221 const x25519_server_pub_key = opt_x25519_server_pub_key orelse243 if (!have_shared_key) return error.TlsIllegalParameter;
222 return error.TlsIllegalParameter;
223 const tls_version = if (supported_version == 0) legacy_version else supported_version;244 const tls_version = if (supported_version == 0) legacy_version else supported_version;
224 switch (tls_version) {245 switch (tls_version) {
225 @enumToInt(tls.ProtocolVersion.tls_1_2) => {246 @enumToInt(tls.ProtocolVersion.tls_1_2) => {
...@@ -231,11 +252,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {...@@ -231,11 +252,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client {
231 else => return error.TlsIllegalParameter,252 else => return error.TlsIllegalParameter,
232 }253 }
233254
234 const shared_key = crypto.dh.X25519.scalarmult(
235 x25519_kp.secret_key,
236 x25519_server_pub_key.*,
237 ) catch return error.TlsDecryptFailure;
238
239 switch (cipher_suite_tag) {255 switch (cipher_suite_tag) {
240 inline .AES_128_GCM_SHA256,256 inline .AES_128_GCM_SHA256,
241 .AES_256_GCM_SHA384,257 .AES_256_GCM_SHA384,