@amritk/nish-x86_64-linux 0.15.0 → 0.16.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.
@@ -6,6 +6,9 @@
6
6
  *
7
7
  * import { x509MintSelfSigned, x509CertificateHash, derToPem } from "nish/crypto/x509";
8
8
  *
9
+ * // Both secrets come from the kernel's CSPRNG; a predictable key or serial is the caller's bug.
10
+ * const priv: u8[] = new Array<u8>(32);
11
+ * crypto.getRandomValues(priv); // p256PublicKey(priv) === null: draw again (odds 2^-32)
9
12
  * const serial: u8[] = new Array<u8>(16);
10
13
  * crypto.getRandomValues(serial);
11
14
  * serial[0] = serial[0] & toU8(0x7f); // positive, so it stays 16 octets
@@ -47,9 +50,11 @@
47
50
  * hash does no path building for basicConstraints or keyUsage to inform, and
48
51
  * every extension would be one more field whose absence is part of the
49
52
  * contract a hash pins. OpenSSL verifies it as its own trust anchor all the
50
- * same (`tests/link/crypto_x509`'s header has the commands). The serial and
51
- * the time are parameters so the golden certificate is deterministic; a caller
52
- * passes `Date.now()` and random bytes.
53
+ * same (`tests/link/crypto_x509`'s header has the commands). The key, the
54
+ * serial and the time are parameters so the golden certificate is
55
+ * deterministic; a caller passes `Date.now()` and, for the key and the serial,
56
+ * bytes from `crypto.getRandomValues`. This module does not draw them itself,
57
+ * because a call to the operating system would stop it compiling for wasm32.
53
58
  *
54
59
  * **Constant time.** A private key is the one secret that passes through here:
55
60
  * it is base64-decoded from PEM, lifted out of its DER, and handed to
@@ -288,12 +293,29 @@ const x509DerSmallInteger = (der: u8[], e: X509DerElement): i32 => {
288
293
  return toI32(der[e.start])
289
294
  }
290
295
 
296
+ /**
297
+ * Whether `e`'s contents are a DER BIT STRING's, whatever its tag (an IMPLICIT
298
+ * one keeps the grammar): an unused-bits count of 0 to 7, none without an
299
+ * octet to hold them, and those bits zero (X.690 §8.6.2 and §11.2.1).
300
+ */
301
+ const x509DerBitStringSound = (der: u8[], e: X509DerElement): boolean => {
302
+ const n: i32 = e.end - e.start
303
+ if (n < 1) {
304
+ return false
305
+ }
306
+ const unused: i32 = toI32(der[e.start])
307
+ if (unused > 7 || (n === 1 && unused !== 0)) {
308
+ return false
309
+ }
310
+ return (toI32(der[e.end - 1]) & ((1 << unused) - 1)) === 0
311
+ }
312
+
291
313
  /**
292
314
  * The octets of a BIT STRING that has no unused bits, or `null`. Keys and
293
315
  * signatures are whole octets, so the leading unused-bits count must be 0.
294
316
  */
295
317
  const x509DerBitStringOctets = (der: u8[], e: X509DerElement): u8[] | null => {
296
- if (e.tag !== X509_TAG_BIT_STRING || e.end - e.start < 1 || toI32(der[e.start]) !== 0) {
318
+ if (e.tag !== X509_TAG_BIT_STRING || !x509DerBitStringSound(der, e) || toI32(der[e.start]) !== 0) {
297
319
  return null
298
320
  }
299
321
  return x509DerSlice(der, e.start + 1, e.end)
@@ -468,9 +490,11 @@ const x509DerUnsignedInto = (der: u8[], e: X509DerElement, out: u8[], off: i32):
468
490
  /**
469
491
  * `r || s`, 32 octets each, out of an ECDSA-Sig-Value `SEQUENCE { INTEGER r,
470
492
  * INTEGER s }` (RFC 5480 §2.2 by way of RFC 3279 §2.2.3), or `null` unless it
471
- * is exactly one with both integers minimal, positive and below 2^256.
493
+ * is exactly one with both integers minimal, positive and below 2^256. This is
494
+ * the form a TLS `CertificateVerify` or an X.509 signature carries, and
495
+ * `nish/crypto/p256` takes the `r || s` it answers.
472
496
  */
473
- const x509DerSignatureRS = (sig: u8[]): u8[] | null => {
497
+ export const x509DerSignatureRS = (sig: u8[]): u8[] | null => {
474
498
  const total: i32 = toI32(sig.length)
475
499
  const seq: X509DerElement | null = x509DerExpect(sig, 0, total, X509_TAG_SEQUENCE)
476
500
  if (seq === null || seq.end !== total) {
@@ -605,6 +629,48 @@ const x509DerTimeAt = (seconds: i64): u8[] => {
605
629
  return x509DerTlv(utc ? X509_TAG_UTC_TIME : X509_TAG_GENERALIZED_TIME, text)
606
630
  }
607
631
 
632
+ /**
633
+ * Whether `bytes` is well-formed UTF-8 (RFC 3629 §4) with no NUL: no stray
634
+ * continuation octet, no truncated sequence, no overlong form, no surrogate and
635
+ * nothing past U+10FFFF. A string in the language is bytes and need not be
636
+ * UTF-8, and a UTF8String that is not UTF-8 is a malformed certificate; a NUL
637
+ * is refused because a name that reads differently to C is the old
638
+ * `localhost\0.example` confusion.
639
+ */
640
+ const x509IsUtf8Name = (bytes: u8[]): boolean => {
641
+ // Continuation octets still owed, and the range the next one must fall in:
642
+ // 80..BF, narrowed after E0, ED, F0 and F4 (Unicode 15 §3.9, Table 3-7).
643
+ let need: i32 = 0
644
+ let lo: i32 = 0x80
645
+ let hi: i32 = 0xbf
646
+ for (let k: i32 = 0; k < toI32(bytes.length); k++) {
647
+ const b: i32 = toI32(bytes[k])
648
+ if (need > 0) {
649
+ if (b < lo || b > hi) {
650
+ return false
651
+ }
652
+ need = need - 1
653
+ lo = 0x80
654
+ hi = 0xbf
655
+ } else if (b === 0) {
656
+ return false
657
+ } else if (b >= 0xc2 && b <= 0xdf) {
658
+ need = 1
659
+ } else if (b >= 0xe0 && b <= 0xef) {
660
+ need = 2
661
+ lo = b === 0xe0 ? 0xa0 : 0x80
662
+ hi = b === 0xed ? 0x9f : 0xbf
663
+ } else if (b >= 0xf0 && b <= 0xf4) {
664
+ need = 3
665
+ lo = b === 0xf0 ? 0x90 : 0x80
666
+ hi = b === 0xf4 ? 0x8f : 0xbf
667
+ } else if (b >= 0x80) {
668
+ return false
669
+ }
670
+ }
671
+ return need === 0
672
+ }
673
+
608
674
  /** The bytes of `text`, as the language holds a string. */
609
675
  const x509Bytes = (text: string): u8[] => {
610
676
  const out: u8[] = []
@@ -790,11 +856,13 @@ export const pemToDer = (pem: string, label: string): u8[][] | null => {
790
856
  if (line !== `-----END ${inside}-----`) {
791
857
  return null
792
858
  }
859
+ // Every block is decoded, whatever its label: a malformed block beside the
860
+ // one asked for is refused, not skipped (docs/security/crypto-x509.md, X509-1).
861
+ const der: u8[] | null = x509Base64Decode(body.join(""))
862
+ if (der === null) {
863
+ return null
864
+ }
793
865
  if (inside === label) {
794
- const der: u8[] | null = x509Base64Decode(body.join(""))
795
- if (der === null) {
796
- return null
797
- }
798
866
  out.push(der)
799
867
  }
800
868
  inside = ""
@@ -882,8 +950,9 @@ const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[]
882
950
  * The scalar of a PKCS#8 PrivateKeyInfo (RFC 5208 §5) or OneAsymmetricKey
883
951
  * (RFC 5958 §2): version 0 or 1, the algorithm id-ecPublicKey with the
884
952
  * prime256v1 curve, and an ECPrivateKey inside the OCTET STRING, followed by
885
- * the optional `[0]` attributes and — in version 1 — `[1]` public key, which
886
- * are skipped.
953
+ * the optional `[0]` attributes, which are skipped, and — in version 1 — the
954
+ * optional `[1]` public key, which must be a BIT STRING of the key's own point
955
+ * (X509-8 in docs/security/crypto-x509.md).
887
956
  */
888
957
  const x509Pkcs8Key = (der: u8[]): u8[] | null => {
889
958
  const total: i32 = toI32(der.length)
@@ -915,17 +984,31 @@ const x509Pkcs8Key = (der: u8[]): u8[] | null => {
915
984
  }
916
985
  at = attributes.end
917
986
  }
987
+ let stored: u8[] | null = null
918
988
  if (v === 1 && x509DerPeek(der, at, seq.end) === 0x81) {
919
- const pub: X509DerElement | null = x509DerRead(der, at, seq.end)
920
- if (pub === null) {
989
+ const outer: X509DerElement | null = x509DerRead(der, at, seq.end)
990
+ if (outer === null) {
921
991
  return null
922
992
  }
923
- at = pub.end
993
+ // `[1] IMPLICIT BIT STRING`: the 0x81 replaces the BIT STRING's own tag,
994
+ // so its contents are the unused-bits octet and then the point.
995
+ const bits: X509DerElement = new X509DerElement(X509_TAG_BIT_STRING, outer.at, outer.start, outer.end)
996
+ stored = x509DerBitStringOctets(der, bits)
997
+ if (stored === null) {
998
+ return null
999
+ }
1000
+ at = outer.end
924
1001
  }
925
1002
  if (at !== seq.end) {
926
1003
  return null
927
1004
  }
928
- return x509Sec1Key(der, key.start, key.end, false)
1005
+ const priv: u8[] | null = x509Sec1Key(der, key.start, key.end, false)
1006
+ if (priv === null || stored === null) {
1007
+ return priv
1008
+ }
1009
+ // The same rule as the SEC1 key's own `[1]`: the stored point is the key's.
1010
+ const pub: u8[] | null = p256PublicKey(priv)
1011
+ return pub !== null && x509BytesEqual(stored, pub) ? priv : null
929
1012
  }
930
1013
 
931
1014
  /**
@@ -953,6 +1036,16 @@ export const x509ParseP256PrivateKey = (pem: string): u8[] | null => {
953
1036
  // Certificates (RFC 5280 §4.1)
954
1037
  // ---------------------------------------------------------------------------
955
1038
 
1039
+ /**
1040
+ * Whether a `[3]` extensions wrapper holds one non-empty SEQUENCE and nothing
1041
+ * after it (RFC 5280 §4.1's `SIZE (1..MAX)`). What an extension says is not
1042
+ * read.
1043
+ */
1044
+ const x509DerExtensionsSound = (der: u8[], e: X509DerElement): boolean => {
1045
+ const seq: X509DerElement | null = x509DerExpect(der, e.start, e.end, X509_TAG_SEQUENCE)
1046
+ return seq !== null && seq.end === e.end && seq.end > seq.start
1047
+ }
1048
+
956
1049
  /**
957
1050
  * `der` read as one Certificate (RFC 5280 §4.1), or `null` unless it is
958
1051
  * exactly one in DER: `SEQUENCE { tbsCertificate, signatureAlgorithm,
@@ -961,8 +1054,16 @@ export const x509ParseP256PrivateKey = (pem: string): u8[] | null => {
961
1054
  * to the outer one byte for byte (§4.1.1.2), issuer and subject Names, a
962
1055
  * Validity of two valid times, a SubjectPublicKeyInfo whose key is whole
963
1056
  * octets, then only the optional `[1]` and `[2]` unique identifiers (v2 and
964
- * v3) and `[3]` extensions (v3), in that order. Any algorithm and key type is
965
- * read; `p256` and `ecdsaSha256` say whether they are this module's.
1057
+ * v3) and `[3]` extensions (v3), in that order, each well formed on the
1058
+ * outside. Any algorithm and key type is read; `p256` and `ecdsaSha256` say
1059
+ * whether they are this module's.
1060
+ *
1061
+ * **A parser, not a validator.** It checks that the bytes are one certificate
1062
+ * and nothing else. It does not check the signature (`x509VerifySignature`
1063
+ * does), that `notBefore` is not after `notAfter` or that either is near any
1064
+ * clock, and it does not read extensions — basicConstraints, keyUsage,
1065
+ * subjectAltName and the critical flag RFC 5280 §4.2 obliges a verifier to
1066
+ * honour are neither checked nor exposed.
966
1067
  */
967
1068
  export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
968
1069
  const total: i32 = toI32(der.length)
@@ -1051,6 +1152,7 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1051
1152
  at = spki.end
1052
1153
  // [1] issuerUniqueID and [2] subjectUniqueID are IMPLICIT BIT STRINGs (so
1053
1154
  // primitive, 0x81 and 0x82) from v2; [3] extensions is explicit (0xa3), v3.
1155
+ // Each is held to its outer shape; what it says is not read.
1054
1156
  const trailing: i32[] = [0x81, 0x82, 0xa3]
1055
1157
  for (let i: i32 = 0; i < 3; i++) {
1056
1158
  if (x509DerPeek(der, at, tbs.end) === trailing[i]) {
@@ -1058,6 +1160,9 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1058
1160
  if (e === null || version < (i === 2 ? 2 : 1)) {
1059
1161
  return null
1060
1162
  }
1163
+ if (i === 2 ? !x509DerExtensionsSound(der, e) : !x509DerBitStringSound(der, e)) {
1164
+ return null
1165
+ }
1061
1166
  at = e.end
1062
1167
  }
1063
1168
  }
@@ -1086,9 +1191,17 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1086
1191
  }
1087
1192
 
1088
1193
  /**
1089
- * Every `CERTIFICATE` block in `pem`, in order — a server's chain, leaf first
1090
- * as TLS sends it — or `null` when there is none, or when any block is not
1091
- * PEM `pemToDer` accepts or a certificate `x509ParseCertificate` accepts.
1194
+ * Every `CERTIFICATE` block in `pem`, in the order they appear — for a
1195
+ * server's chain file, leaf first as TLS sends it — or `null` when there is
1196
+ * none, or when any block is not PEM `pemToDer` accepts or a certificate
1197
+ * `x509ParseCertificate` accepts.
1198
+ *
1199
+ * **It reads a chain; it does not validate one.** Nothing relates one
1200
+ * certificate to the next: not the order, not that each is issued by the one
1201
+ * after it (issuer against subject, or signature), not validity against a
1202
+ * clock, basicConstraints, keyUsage, name constraints or a trust anchor. RFC
1203
+ * 5280 §6's path validation is not in this module, and a chain it answers is
1204
+ * no evidence that anyone vouches for the leaf.
1092
1205
  */
1093
1206
  export const x509ParseChain = (pem: string): X509Certificate[] | null => {
1094
1207
  const blocks: u8[][] | null = pemToDer(pem, "CERTIFICATE")
@@ -1110,8 +1223,11 @@ export const x509ParseChain = (pem: string): X509Certificate[] | null => {
1110
1223
  * Whether `cert`'s signature is a valid ecdsa-with-SHA256 signature of its TBS
1111
1224
  * bytes under `issuer`'s P-256 key — a self-signed certificate passes itself
1112
1225
  * as both. `false` for any other algorithm or key, and for a signature that is
1113
- * not a DER ECDSA-Sig-Value. Only the signature: names, times and extensions
1114
- * are the caller's policy.
1226
+ * not a DER ECDSA-Sig-Value. Only the signature: that `cert.issuer` is
1227
+ * `issuer.subject` and that the times hold are fields the caller compares, and
1228
+ * whether `issuer` may issue at all (basicConstraints, keyUsage) is in
1229
+ * extensions this module does not read, so a `true` here is not path
1230
+ * validation.
1115
1231
  */
1116
1232
  export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certificate): boolean => {
1117
1233
  if (!cert.ecdsaSha256 || !issuer.p256) {
@@ -1131,8 +1247,9 @@ export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certifica
1131
1247
  * `serial`, and signed with ecdsa-with-SHA256 — see the module comment for why
1132
1248
  * it has no extensions. `null` when `days` is below 1 or above
1133
1249
  * `X509_MAX_DAYS`, `notBeforeMs` is negative or the validity would end after
1134
- * 9999, `commonName` is empty or longer than 64 bytes, `priv` is not a P-256
1135
- * private key, or `serial` — big-endian, leading zeros ignored — is zero or
1250
+ * 9999, `commonName` is empty, longer than 64 bytes, not UTF-8 or holds a NUL
1251
+ * (it is written as a UTF8String), `priv` is not a P-256 private key, or
1252
+ * `serial` — big-endian, leading zeros ignored — is zero or
1136
1253
  * needs more than `X509_MAX_SERIAL` octets as a positive INTEGER (clear the top
1137
1254
  * bit of 20 random bytes, or use fewer).
1138
1255
  */
@@ -1154,7 +1271,7 @@ export const x509MintSelfSigned = (
1154
1271
  }
1155
1272
  const name: u8[] = x509Bytes(commonName)
1156
1273
  const nameLength: i32 = toI32(name.length)
1157
- if (nameLength < 1 || nameLength > X509_MAX_COMMON_NAME) {
1274
+ if (nameLength < 1 || nameLength > X509_MAX_COMMON_NAME || !x509IsUtf8Name(name)) {
1158
1275
  return null
1159
1276
  }
1160
1277
  const serialDer: u8[] = x509DerUnsignedInteger(serial)