| author | |
| committer | |
| log | 3237000d957617120e32e54498cac9afa23cbcd4 |
| tree | 03fc00c8b7738b38db7264c27f3021e8fdedf0e7 |
| parent | 5d7eca6669228cec762fc9063a7ea3cb52af357c |
2 files changed, 174 insertions(+), 1 deletions(-)
lib/std/crypto/tls.zig+109| ... | @@ -349,3 +349,112 @@ pub inline fn int3(x: u24) [3]u8 { | ... | @@ -349,3 +349,112 @@ pub inline fn int3(x: u24) [3]u8 { |
| 349 | @truncate(u8, x), | 349 | @truncate(u8, x), |
| 350 | }; | 350 | }; |
| 351 | } | 351 | } |
| 352 | |||
| 353 | pub const Der = struct { | ||
| 354 | pub const Class = enum(u2) { | ||
| 355 | universal, | ||
| 356 | application, | ||
| 357 | context_specific, | ||
| 358 | private, | ||
| 359 | }; | ||
| 360 | |||
| 361 | pub const PC = enum(u1) { | ||
| 362 | primitive, | ||
| 363 | constructed, | ||
| 364 | }; | ||
| 365 | |||
| 366 | pub const Identifier = packed struct(u8) { | ||
| 367 | tag: Tag, | ||
| 368 | pc: PC, | ||
| 369 | class: Class, | ||
| 370 | }; | ||
| 371 | |||
| 372 | pub const Tag = enum(u5) { | ||
| 373 | boolean = 1, | ||
| 374 | integer = 2, | ||
| 375 | bitstring = 3, | ||
| 376 | null = 5, | ||
| 377 | object_identifier = 6, | ||
| 378 | sequence = 16, | ||
| 379 | _, | ||
| 380 | }; | ||
| 381 | |||
| 382 | pub const Oid = enum { | ||
| 383 | commonName, | ||
| 384 | countryName, | ||
| 385 | localityName, | ||
| 386 | stateOrProvinceName, | ||
| 387 | organizationName, | ||
| 388 | organizationalUnitName, | ||
| 389 | sha256WithRSAEncryption, | ||
| 390 | sha384WithRSAEncryption, | ||
| 391 | sha512WithRSAEncryption, | ||
| 392 | sha224WithRSAEncryption, | ||
| 393 | |||
| 394 | pub const map = std.ComptimeStringMap(Oid, .{ | ||
| 395 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, | ||
| 396 | .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName }, | ||
| 397 | .{ &[_]u8{ 0x55, 0x04, 0x07 }, .localityName }, | ||
| 398 | .{ &[_]u8{ 0x55, 0x04, 0x08 }, .stateOrProvinceName }, | ||
| 399 | .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName }, | ||
| 400 | .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName }, | ||
| 401 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B }, .sha256WithRSAEncryption }, | ||
| 402 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C }, .sha384WithRSAEncryption }, | ||
| 403 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D }, .sha512WithRSAEncryption }, | ||
| 404 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E }, .sha224WithRSAEncryption }, | ||
| 405 | }); | ||
| 406 | }; | ||
| 407 | |||
| 408 | pub const Element = struct { | ||
| 409 | identifier: Identifier, | ||
| 410 | contents: []const u8, | ||
| 411 | }; | ||
| 412 | |||
| 413 | pub const ParseElementError = error{CertificateHasFieldWithInvalidLength}; | ||
| 414 | |||
| 415 | pub fn parseElement(bytes: []const u8, index: *usize) ParseElementError!Der.Element { | ||
| 416 | var i = index.*; | ||
| 417 | const identifier = @bitCast(Identifier, bytes[i]); | ||
| 418 | i += 1; | ||
| 419 | const size_byte = bytes[i]; | ||
| 420 | i += 1; | ||
| 421 | if ((size_byte >> 7) == 0) { | ||
| 422 | const contents = bytes[i..][0..size_byte]; | ||
| 423 | index.* = i + contents.len; | ||
| 424 | return .{ | ||
| 425 | .identifier = identifier, | ||
| 426 | .contents = contents, | ||
| 427 | }; | ||
| 428 | } | ||
| 429 | |||
| 430 | const len_size = @truncate(u7, size_byte); | ||
| 431 | if (len_size > @sizeOf(usize)) { | ||
| 432 | return error.CertificateHasFieldWithInvalidLength; | ||
| 433 | } | ||
| 434 | |||
| 435 | const end = i + len_size; | ||
| 436 | var long_form_size: usize = 0; | ||
| 437 | while (i < end) : (i += 1) { | ||
| 438 | long_form_size = (long_form_size << 8) | bytes[i]; | ||
| 439 | } | ||
| 440 | |||
| 441 | const contents = bytes[i..][0..long_form_size]; | ||
| 442 | index.* = i + contents.len; | ||
| 443 | |||
| 444 | return .{ | ||
| 445 | .identifier = identifier, | ||
| 446 | .contents = contents, | ||
| 447 | }; | ||
| 448 | } | ||
| 449 | |||
| 450 | pub const ParseObjectIdError = error{ | ||
| 451 | CertificateHasUnrecognizedObjectId, | ||
| 452 | CertificateFieldHasWrongDataType, | ||
| 453 | } || ParseElementError; | ||
| 454 | |||
| 455 | pub fn parseObjectId(bytes: []const u8, index: *usize) ParseObjectIdError!Oid { | ||
| 456 | const oid_element = try parseElement(bytes, index); | ||
| 457 | if (oid_element.identifier.tag != .object_identifier) return error.CertificateFieldHasWrongDataType; | ||
| 458 | return Oid.map.get(oid_element.contents) orelse return error.CertificateHasUnrecognizedObjectId; | ||
| 459 | } | ||
| 460 | }; |
lib/std/crypto/tls/Client.zig+65-1| ... | @@ -402,7 +402,71 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { | ... | @@ -402,7 +402,71 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 402 | while (hs_i < end_certs) { | 402 | while (hs_i < end_certs) { |
| 403 | const cert_size = mem.readIntBig(u24, handshake[hs_i..][0..3]); | 403 | const cert_size = mem.readIntBig(u24, handshake[hs_i..][0..3]); |
| 404 | hs_i += 3; | 404 | hs_i += 3; |
| 405 | hs_i += cert_size; | 405 | const end_cert = hs_i + cert_size; |
| 406 | |||
| 407 | const certificate = try tls.Der.parseElement(handshake, &hs_i); | ||
| 408 | { | ||
| 409 | var cert_i: usize = 0; | ||
| 410 | const tbs_certificate = try tls.Der.parseElement(certificate.contents, &cert_i); | ||
| 411 | { | ||
| 412 | var tbs_i: usize = 0; | ||
| 413 | const version = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 414 | const serial_number = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 415 | const signature = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 416 | const issuer = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 417 | const validity = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 418 | const subject = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 419 | const subject_pub_key = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 420 | const extensions = try tls.Der.parseElement(tbs_certificate.contents, &tbs_i); | ||
| 421 | |||
| 422 | // RFC 5280, section 4.1.2.3: | ||
| 423 | // "This field MUST contain the same algorithm identifier as | ||
| 424 | // the signatureAlgorithm field in the sequence Certificate." | ||
| 425 | _ = signature; | ||
| 426 | |||
| 427 | _ = issuer; | ||
| 428 | _ = validity; | ||
| 429 | |||
| 430 | std.debug.print("version: {any} '{}'\n", .{ | ||
| 431 | version.identifier, std.fmt.fmtSliceHexLower(version.contents), | ||
| 432 | }); | ||
| 433 | |||
| 434 | std.debug.print("serial_number: {any} {}\n", .{ | ||
| 435 | serial_number.identifier, | ||
| 436 | std.fmt.fmtSliceHexLower(serial_number.contents), | ||
| 437 | }); | ||
| 438 | |||
| 439 | std.debug.print("subject: {any} {}\n", .{ | ||
| 440 | subject.identifier, | ||
| 441 | std.fmt.fmtSliceHexLower(subject.contents), | ||
| 442 | }); | ||
| 443 | |||
| 444 | std.debug.print("subject pub key: {any} {}\n", .{ | ||
| 445 | subject_pub_key.identifier, | ||
| 446 | std.fmt.fmtSliceHexLower(subject_pub_key.contents), | ||
| 447 | }); | ||
| 448 | |||
| 449 | std.debug.print("extensions: {any} {}\n", .{ | ||
| 450 | extensions.identifier, | ||
| 451 | std.fmt.fmtSliceHexLower(extensions.contents), | ||
| 452 | }); | ||
| 453 | } | ||
| 454 | const signature_algorithm = try tls.Der.parseElement(certificate.contents, &cert_i); | ||
| 455 | const signature_value = try tls.Der.parseElement(certificate.contents, &cert_i); | ||
| 456 | |||
| 457 | { | ||
| 458 | var sa_i: usize = 0; | ||
| 459 | const algorithm = try tls.Der.parseObjectId(signature_algorithm.contents, &sa_i); | ||
| 460 | std.debug.print("cert has this signature algorithm: {any}\n", .{algorithm}); | ||
| 461 | //const parameters = try tls.Der.parseElement(signature_algorithm.contents, &sa_i); | ||
| 462 | } | ||
| 463 | |||
| 464 | std.debug.print("signature_value: {any} {d} bytes\n", .{ | ||
| 465 | signature_value.identifier, signature_value.contents.len, | ||
| 466 | }); | ||
| 467 | } | ||
| 468 | |||
| 469 | hs_i = end_cert; | ||
| 406 | const total_ext_size = mem.readIntBig(u16, handshake[hs_i..][0..2]); | 470 | const total_ext_size = mem.readIntBig(u16, handshake[hs_i..][0..2]); |
| 407 | hs_i += 2; | 471 | hs_i += 2; |
| 408 | hs_i += total_ext_size; | 472 | hs_i += total_ext_size; |