@amritk/nish-x86_64-linux 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +43 -34
- package/bin/nish +0 -0
- package/package.json +1 -1
- package/runtime/nish.d.ts +117 -8
- package/runtime/nish.h +50 -13
- package/runtime/nish.mjs +71 -7
- package/runtime/runtime-host.c +43 -24
- package/runtime/runtime-net.c +57 -10
- package/runtime/runtime-os.c +62 -20
- package/runtime/runtime-simd.c +203 -0
- package/runtime/runtime-wasm.c +12 -0
- package/runtime/runtime.c +66 -18
- package/runtime/shim.mjs +114 -5
- package/scripts/build.sh +14 -12
- package/std/README.md +168 -36
- package/std/crypto/aes.ts +51 -8
- package/std/crypto/base64url.ts +25 -12
- package/std/crypto/chacha20poly1305.ts +43 -29
- package/std/crypto/ct.ts +6 -1
- package/std/crypto/hkdf.ts +364 -3
- package/std/crypto/hmac.ts +307 -7
- package/std/crypto/p256.ts +618 -34
- package/std/crypto/sha1.ts +147 -0
- package/std/crypto/sha256.ts +3 -2
- package/std/crypto/x25519.ts +88 -36
- package/std/crypto/x509.ts +130 -47
- package/std/json.ts +297 -41
- package/std/net/hpack.ts +1094 -0
- package/std/net/http-fields.ts +604 -0
- package/std/net/http1-server.ts +1389 -0
- package/std/net/http1.ts +1492 -0
- package/std/net/http2-frame.ts +745 -0
- package/std/net/http2-tls.ts +216 -0
- package/std/net/http2.ts +1433 -0
- package/std/net/http3-frame.ts +457 -0
- package/std/net/http3-server.ts +911 -0
- package/std/net/http3.ts +2145 -0
- package/std/net/qpack.ts +1163 -0
- package/std/net/quic-conn-ack.ts +206 -0
- package/std/net/quic-conn-cid.ts +425 -0
- package/std/net/quic-conn-params.ts +462 -0
- package/std/net/quic-datagram.ts +130 -0
- package/std/net/quic-frame.ts +1206 -0
- package/std/net/quic-listener.ts +929 -0
- package/std/net/quic-packet.ts +1698 -0
- package/std/net/quic-recovery.ts +849 -0
- package/std/net/quic-stream.ts +1609 -0
- package/std/net/quic.ts +3578 -0
- package/std/net/tls/codec.ts +1089 -0
- package/std/net/tls/record-server.ts +1173 -0
- package/std/net/tls/record.ts +621 -0
- package/std/net/tls/schedule.ts +429 -0
- package/std/net/tls-tcp.ts +414 -0
- package/std/net/tls.ts +1437 -0
- package/std/net/websocket.ts +823 -0
- package/std/net/webtransport.ts +1334 -0
- package/std/secret.ts +62 -0
- package/std/text.ts +77 -0
package/std/crypto/x509.ts
CHANGED
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
* import { x509MintSelfSigned, x509CertificateHash, derToPem } from "nish/crypto/x509";
|
|
8
8
|
*
|
|
9
9
|
* // Both secrets come from the kernel's CSPRNG; a predictable key or serial is the caller's bug.
|
|
10
|
-
* const
|
|
11
|
-
* crypto.getRandomValues(
|
|
10
|
+
* const drawn: u8[] = new Array<u8>(32);
|
|
11
|
+
* crypto.getRandomValues(drawn);
|
|
12
|
+
* const priv: Secret<u8[]> = secret(drawn); // nish:secret; p256PublicKey(priv) === null: draw again (odds 2^-32)
|
|
12
13
|
* const serial: u8[] = new Array<u8>(16);
|
|
13
14
|
* crypto.getRandomValues(serial);
|
|
14
15
|
* serial[0] = serial[0] & toU8(0x7f); // positive, so it stays 16 octets
|
|
15
16
|
* const der: u8[] | null = x509MintSelfSigned(priv, "localhost", toI64(Date.now()), 14, serial);
|
|
17
|
+
* wipe(priv);
|
|
16
18
|
* // x509CertificateHash(der) is what serverCertificateHashes names;
|
|
17
19
|
* // derToPem(der, "CERTIFICATE") is the file a TLS stack loads.
|
|
18
20
|
*
|
|
@@ -31,7 +33,8 @@
|
|
|
31
33
|
* `null`, never a panic. The reader looks at what this module uses — the
|
|
32
34
|
* version, serial, algorithms, names as opaque bytes, validity, the subject
|
|
33
35
|
* public key and the signature — and checks the order of what follows the key
|
|
34
|
-
* (`[1]`, `[2]`, `[3]`) without parsing extensions
|
|
36
|
+
* (`[1]`, `[2]`, `[3]`) without parsing extensions; the mint writes two of its
|
|
37
|
+
* own (below).
|
|
35
38
|
*
|
|
36
39
|
* **PEM is RFC 7468's strict grammar**, with standard base64 (`+` and `/`,
|
|
37
40
|
* padded with `=`), not `base64url`: 64 characters a line and a shorter last
|
|
@@ -45,15 +48,26 @@
|
|
|
45
48
|
* requirements"): X.509 v3, an ECDSA P-256 key signed with ecdsa-with-SHA256,
|
|
46
49
|
* and a validity period of at most fourteen days — `notAfter - notBefore`,
|
|
47
50
|
* which is what Chromium compares, so `days` is 1 to 14. Subject and issuer
|
|
48
|
-
* are the same single common name, as a UTF8String. It carries **
|
|
49
|
-
* extensions
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
51
|
+
* are the same single common name, as a UTF8String. It carries **two
|
|
52
|
+
* extensions, both critical and both constant**: basicConstraints with cA
|
|
53
|
+
* FALSE and keyUsage with digitalSignature alone. The W3C text requires no
|
|
54
|
+
* extension, but Chromium does: the verifier behind `serverCertificateHashes`,
|
|
55
|
+
* quiche's `WebTransportFingerprintProofVerifier`, parses the certificate
|
|
56
|
+
* with `CertificateView::ParseSingleCertificate` before it compares the hash,
|
|
57
|
+
* and that answers null when `[3] extensions` is absent
|
|
58
|
+
* (`quiche/quic/core/crypto/certificate_view.cc:395`, at the quiche revision
|
|
59
|
+
* 62826931 Chromium 141 pins), so the handshake fails with
|
|
60
|
+
* CERTIFICATE_VERIFY_FAILED. It also holds every extension to `SEQUENCE {
|
|
61
|
+
* OID, BOOLEAN OPTIONAL, OCTET STRING }` (`:413`–`:432`) and reads
|
|
62
|
+
* subjectAltName only when one is present (`:434`), so no name is needed
|
|
63
|
+
* there. The two chosen say what the certificate is, an end entity whose key
|
|
64
|
+
* only signs handshakes, so a verifier that does build a path need not fall
|
|
65
|
+
* back on its defaults; OpenSSL verifies it as its own trust anchor
|
|
66
|
+
* (`tests/link/crypto_x509`'s header has the commands; X509-9 in
|
|
67
|
+
* docs/security/crypto-x509.md). The key, the serial and the time are
|
|
68
|
+
* parameters so the golden certificate is deterministic; a caller passes
|
|
69
|
+
* `Date.now()` and, for the key and the serial, bytes from
|
|
70
|
+
* `crypto.getRandomValues`. This module does not draw them itself,
|
|
57
71
|
* because a call to the operating system would stop it compiling for wasm32.
|
|
58
72
|
*
|
|
59
73
|
* **Constant time.** A private key is the one secret that passes through here:
|
|
@@ -70,10 +84,18 @@
|
|
|
70
84
|
* public key stored beside it compares public values. None of this is under
|
|
71
85
|
* the disassembly check; it is discipline.
|
|
72
86
|
*
|
|
87
|
+
* **The private key is a `Secret`** (`nish:secret`, docs/LANGUAGE.md
|
|
88
|
+
* "Secrets"). `x509ParseP256PrivateKey` answers one and `x509MintSelfSigned`
|
|
89
|
+
* takes one; the scalar is copied out of its DER once, into the `Secret`, and
|
|
90
|
+
* every block decoded from the PEM is wiped before the parse returns (X509-7,
|
|
91
|
+
* docs/security/crypto-x509.md). The PEM text is the caller's string, which
|
|
92
|
+
* nothing in the language can wipe.
|
|
93
|
+
*
|
|
73
94
|
* Private names carry the `x509` prefix because a `std/` module's private
|
|
74
95
|
* functions share the importing program's flat symbol namespace
|
|
75
96
|
* (`docs/wp26-stdlib.md` §3e).
|
|
76
97
|
*/
|
|
98
|
+
import { Secret, secret, wipe } from "nish:secret"
|
|
77
99
|
import { p256PublicKey, p256SignSha256, p256VerifySha256 } from "nish/crypto/p256"
|
|
78
100
|
import { sha256 } from "nish/crypto/sha256"
|
|
79
101
|
|
|
@@ -685,8 +707,15 @@ const x509Bytes = (text: string): u8[] => {
|
|
|
685
707
|
// PEM (RFC 7468) and standard base64 (RFC 4648 §4)
|
|
686
708
|
// ---------------------------------------------------------------------------
|
|
687
709
|
|
|
688
|
-
/**
|
|
689
|
-
|
|
710
|
+
/**
|
|
711
|
+
* All ones when `lo <= c <= hi`, else zero, without a branch; `c` is a byte or
|
|
712
|
+
* a sextet. The subtractions are `u32`'s, which wrap by definition, rather
|
|
713
|
+
* than checked `i32` ones, whose check would be a branch on a byte of what may
|
|
714
|
+
* be a private key's PEM; the sign bit `>> 31` reads is the same.
|
|
715
|
+
* `x509Base64CharOf` and `x509Base64SextetOf` sum in `u32` for the same reason.
|
|
716
|
+
*/
|
|
717
|
+
const x509RangeMask = (c: i32, lo: i32, hi: i32): i32 =>
|
|
718
|
+
toI32((toU32(lo) - 1 - toU32(c)) & (toU32(c) - toU32(hi) - 1)) >> 31
|
|
690
719
|
|
|
691
720
|
/**
|
|
692
721
|
* The base64 character for the sextet `v`: `'A' + v`, stepped by the gap to
|
|
@@ -694,12 +723,14 @@ const x509RangeMask = (c: i32, lo: i32, hi: i32): i32 => ((lo - 1 - c) & (c - hi
|
|
|
694
723
|
* 63 on `/`.
|
|
695
724
|
*/
|
|
696
725
|
const x509Base64CharOf = (v: i32): i32 =>
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
726
|
+
toI32(
|
|
727
|
+
65 +
|
|
728
|
+
toU32(v) +
|
|
729
|
+
toU32(x509RangeMask(v, 26, 63) & 6) -
|
|
730
|
+
toU32(x509RangeMask(v, 52, 63) & 75) -
|
|
731
|
+
toU32(x509RangeMask(v, 62, 63) & 15) +
|
|
732
|
+
toU32(x509RangeMask(v, 63, 63) & 3)
|
|
733
|
+
)
|
|
703
734
|
|
|
704
735
|
/** The sextet the byte `c` stands for in base64, or `-1` when it is not in the alphabet. */
|
|
705
736
|
const x509Base64SextetOf = (c: i32): i32 => {
|
|
@@ -708,7 +739,12 @@ const x509Base64SextetOf = (c: i32): i32 => {
|
|
|
708
739
|
const digit: i32 = x509RangeMask(c, 48, 57)
|
|
709
740
|
const plus: i32 = x509RangeMask(c, 43, 43)
|
|
710
741
|
const slash: i32 = x509RangeMask(c, 47, 47)
|
|
711
|
-
const value: i32 =
|
|
742
|
+
const value: i32 =
|
|
743
|
+
(upper & toI32(toU32(c) - 65)) |
|
|
744
|
+
(lower & toI32(toU32(c) - 71)) |
|
|
745
|
+
(digit & toI32(toU32(c) + 4)) |
|
|
746
|
+
(plus & 62) |
|
|
747
|
+
(slash & 63)
|
|
712
748
|
return value | ~(upper | lower | digit | plus | slash)
|
|
713
749
|
}
|
|
714
750
|
|
|
@@ -892,7 +928,7 @@ export const pemToDer = (pem: string, label: string): u8[][] | null => {
|
|
|
892
928
|
* optional `[1]` public key, which must be the key's own. `null` otherwise,
|
|
893
929
|
* or when the scalar is 0 or not below n.
|
|
894
930
|
*/
|
|
895
|
-
const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[] | null => {
|
|
931
|
+
const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): Secret<u8[]> | null => {
|
|
896
932
|
const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
|
|
897
933
|
if (seq === null || seq.end !== end) {
|
|
898
934
|
return null
|
|
@@ -905,7 +941,6 @@ const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[]
|
|
|
905
941
|
if (key === null || key.end - key.start !== 32) {
|
|
906
942
|
return null
|
|
907
943
|
}
|
|
908
|
-
const priv: u8[] = x509DerSlice(der, key.start, key.end)
|
|
909
944
|
let at: i32 = key.end
|
|
910
945
|
let curve: boolean = false
|
|
911
946
|
let stored: u8[] | null = null
|
|
@@ -935,12 +970,13 @@ const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[]
|
|
|
935
970
|
if (at !== seq.end || (needCurve && !curve)) {
|
|
936
971
|
return null
|
|
937
972
|
}
|
|
938
|
-
//
|
|
973
|
+
// The scalar is copied out of the DER only once the structure is known to
|
|
974
|
+
// be sound, straight into the `Secret` that owns it (X509-7). The check
|
|
975
|
+
// refuses 0 and n and above, and gives the point to hold `stored` against.
|
|
976
|
+
const priv: Secret<u8[]> = secret(x509DerSlice(der, key.start, key.end))
|
|
939
977
|
const pub: u8[] | null = p256PublicKey(priv)
|
|
940
|
-
if (pub === null) {
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
if (stored !== null && !x509BytesEqual(stored, pub)) {
|
|
978
|
+
if (pub === null || (stored !== null && !x509BytesEqual(stored, pub))) {
|
|
979
|
+
wipe(priv)
|
|
944
980
|
return null
|
|
945
981
|
}
|
|
946
982
|
return priv
|
|
@@ -954,7 +990,7 @@ const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[]
|
|
|
954
990
|
* optional `[1]` public key, which must be a BIT STRING of the key's own point
|
|
955
991
|
* (X509-8 in docs/security/crypto-x509.md).
|
|
956
992
|
*/
|
|
957
|
-
const x509Pkcs8Key = (der: u8[]): u8[] | null => {
|
|
993
|
+
const x509Pkcs8Key = (der: u8[]): Secret<u8[]> | null => {
|
|
958
994
|
const total: i32 = toI32(der.length)
|
|
959
995
|
const seq: X509DerElement | null = x509DerExpect(der, 0, total, X509_TAG_SEQUENCE)
|
|
960
996
|
if (seq === null || seq.end !== total) {
|
|
@@ -1002,34 +1038,54 @@ const x509Pkcs8Key = (der: u8[]): u8[] | null => {
|
|
|
1002
1038
|
if (at !== seq.end) {
|
|
1003
1039
|
return null
|
|
1004
1040
|
}
|
|
1005
|
-
const priv: u8[] | null = x509Sec1Key(der, key.start, key.end, false)
|
|
1041
|
+
const priv: Secret<u8[]> | null = x509Sec1Key(der, key.start, key.end, false)
|
|
1006
1042
|
if (priv === null || stored === null) {
|
|
1007
1043
|
return priv
|
|
1008
1044
|
}
|
|
1009
1045
|
// The same rule as the SEC1 key's own `[1]`: the stored point is the key's.
|
|
1010
1046
|
const pub: u8[] | null = p256PublicKey(priv)
|
|
1011
|
-
|
|
1047
|
+
if (pub === null || !x509BytesEqual(stored, pub)) {
|
|
1048
|
+
wipe(priv)
|
|
1049
|
+
return null
|
|
1050
|
+
}
|
|
1051
|
+
return priv
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/** Zero every block `pemToDer` decoded: a private key's DER is key material, refused or not. */
|
|
1055
|
+
const x509WipeBlocks = (blocks: u8[][] | null): void => {
|
|
1056
|
+
if (blocks === null) {
|
|
1057
|
+
return
|
|
1058
|
+
}
|
|
1059
|
+
for (const block of blocks) {
|
|
1060
|
+
wipe(block)
|
|
1061
|
+
}
|
|
1012
1062
|
}
|
|
1013
1063
|
|
|
1014
1064
|
/**
|
|
1015
|
-
* The 32-byte P-256 private key in `pem
|
|
1016
|
-
* RFC 5915, which must name its curve) or one
|
|
1017
|
-
* PKCS#8, RFC 5208 or RFC 5958), and not both.
|
|
1018
|
-
* more than one, for any curve but P-256, for a
|
|
1019
|
-
* a stored public key that is not the key's own,
|
|
1020
|
-
* An `ENCRYPTED PRIVATE KEY` is a different label,
|
|
1065
|
+
* The 32-byte P-256 private key in `pem`, as the `Secret` it is: one `EC
|
|
1066
|
+
* PRIVATE KEY` block (SEC1, RFC 5915, which must name its curve) or one
|
|
1067
|
+
* `PRIVATE KEY` block (unencrypted PKCS#8, RFC 5208 or RFC 5958), and not both.
|
|
1068
|
+
* `null` for no such block or more than one, for any curve but P-256, for a
|
|
1069
|
+
* scalar of 0 or n or more, for a stored public key that is not the key's own,
|
|
1070
|
+
* and for anything malformed. An `ENCRYPTED PRIVATE KEY` is a different label,
|
|
1071
|
+
* and answers `null`. Every block decoded from `pem` is wiped before this
|
|
1072
|
+
* returns, whichever answer it gives; `pem` itself is the caller's string,
|
|
1073
|
+
* which nothing can wipe (X509-7 in docs/security/crypto-x509.md).
|
|
1021
1074
|
*/
|
|
1022
|
-
export const x509ParseP256PrivateKey = (pem: string): u8[] | null => {
|
|
1075
|
+
export const x509ParseP256PrivateKey = (pem: string): Secret<u8[]> | null => {
|
|
1023
1076
|
const sec1: u8[][] | null = pemToDer(pem, "EC PRIVATE KEY")
|
|
1024
1077
|
const pkcs8: u8[][] | null = pemToDer(pem, "PRIVATE KEY")
|
|
1078
|
+
let key: Secret<u8[]> | null = null
|
|
1025
1079
|
if (sec1 !== null && pkcs8 === null && toI32(sec1.length) === 1) {
|
|
1026
1080
|
const der: u8[] = sec1[0]
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1081
|
+
key = x509Sec1Key(der, 0, toI32(der.length), true)
|
|
1082
|
+
} else if (pkcs8 !== null && sec1 === null && toI32(pkcs8.length) === 1) {
|
|
1083
|
+
key = x509Pkcs8Key(pkcs8[0])
|
|
1084
|
+
}
|
|
1085
|
+
// X509-7: the decoded DER holds the scalar too, whichever block it was.
|
|
1086
|
+
x509WipeBlocks(sec1)
|
|
1087
|
+
x509WipeBlocks(pkcs8)
|
|
1088
|
+
return key
|
|
1033
1089
|
}
|
|
1034
1090
|
|
|
1035
1091
|
// ---------------------------------------------------------------------------
|
|
@@ -1240,12 +1296,38 @@ export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certifica
|
|
|
1240
1296
|
return p256VerifySha256(issuer.publicKey, cert.tbs, rs)
|
|
1241
1297
|
}
|
|
1242
1298
|
|
|
1299
|
+
/**
|
|
1300
|
+
* The minted certificate's `[3] extensions`, whole, in DER. They do not depend
|
|
1301
|
+
* on the key, the name or the time, so they are one constant block rather
|
|
1302
|
+
* than a tree of `x509DerWrap` calls (`tests/link/crypto_x509` pins each
|
|
1303
|
+
* octet, and `x509ParseCertificate` reads the result back):
|
|
1304
|
+
*
|
|
1305
|
+
* a3 20 [3] EXPLICIT, 32 octets
|
|
1306
|
+
* 30 1e Extensions SEQUENCE, 30 octets
|
|
1307
|
+
* 30 0c Extension (RFC 5280 §4.2.1.9)
|
|
1308
|
+
* 06 03 55 1d 13 basicConstraints, 2.5.29.19
|
|
1309
|
+
* 01 01 ff critical TRUE
|
|
1310
|
+
* 04 02 30 00 OCTET STRING { SEQUENCE {} }: cA FALSE is the
|
|
1311
|
+
* DEFAULT, so DER leaves it out (X.690 §11.5)
|
|
1312
|
+
* 30 0e Extension (RFC 5280 §4.2.1.3)
|
|
1313
|
+
* 06 03 55 1d 0f keyUsage, 2.5.29.15
|
|
1314
|
+
* 01 01 ff critical TRUE
|
|
1315
|
+
* 04 04 03 02 07 80 OCTET STRING { BIT STRING, 7 unused bits,
|
|
1316
|
+
* bit 0 digitalSignature }: DER drops a named
|
|
1317
|
+
* bit list's trailing zero bits (X.690 §11.2.2)
|
|
1318
|
+
*/
|
|
1319
|
+
const x509MintExtensions = (): u8[] => [
|
|
1320
|
+
0xa3, 0x20, 0x30, 0x1e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
|
|
1321
|
+
0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
|
|
1322
|
+
]
|
|
1323
|
+
|
|
1243
1324
|
/**
|
|
1244
1325
|
* A self-signed X.509 v3 certificate, in DER, for the P-256 key `priv`: subject
|
|
1245
1326
|
* and issuer `CN=commonName`, valid from `notBeforeMs` (milliseconds since
|
|
1246
1327
|
* 1970, rounded down to the second) for exactly `days` days, serial number
|
|
1247
|
-
* `serial`,
|
|
1248
|
-
*
|
|
1328
|
+
* `serial`, carrying `x509MintExtensions`' basicConstraints and keyUsage, and
|
|
1329
|
+
* signed with ecdsa-with-SHA256 — see the module comment for why Chromium
|
|
1330
|
+
* needs an extension at all. `null` when `days` is below 1 or above
|
|
1249
1331
|
* `X509_MAX_DAYS`, `notBeforeMs` is negative or the validity would end after
|
|
1250
1332
|
* 9999, `commonName` is empty, longer than 64 bytes, not UTF-8 or holds a NUL
|
|
1251
1333
|
* (it is written as a UTF8String), `priv` is not a P-256 private key, or
|
|
@@ -1254,7 +1336,7 @@ export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certifica
|
|
|
1254
1336
|
* bit of 20 random bytes, or use fewer).
|
|
1255
1337
|
*/
|
|
1256
1338
|
export const x509MintSelfSigned = (
|
|
1257
|
-
priv: u8[]
|
|
1339
|
+
priv: Secret<u8[]>,
|
|
1258
1340
|
commonName: string,
|
|
1259
1341
|
notBeforeMs: i64,
|
|
1260
1342
|
days: i32,
|
|
@@ -1312,6 +1394,7 @@ export const x509MintSelfSigned = (
|
|
|
1312
1394
|
x509DerWrap(X509_TAG_SEQUENCE, [x509DerTimeAt(start), x509DerTimeAt(end)]),
|
|
1313
1395
|
distinguished,
|
|
1314
1396
|
spki,
|
|
1397
|
+
x509MintExtensions(),
|
|
1315
1398
|
])
|
|
1316
1399
|
const rs: u8[] | null = p256SignSha256(priv, tbs)
|
|
1317
1400
|
if (rs === null) {
|