sm-crypto-wasm 0.7.0 → 0.7.1

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.
Files changed (126) hide show
  1. package/README.md +41 -876
  2. package/dist/asn1/decode.d.ts +103 -12
  3. package/dist/asn1/decode.js +129 -10
  4. package/dist/asn1/encode.d.ts +120 -19
  5. package/dist/asn1/encode.js +158 -19
  6. package/dist/asn1/index.d.ts +6 -0
  7. package/dist/asn1/index.js +6 -0
  8. package/dist/asn1/oid.d.ts +18 -0
  9. package/dist/asn1/oid.js +30 -1
  10. package/dist/asn1/time.d.ts +32 -0
  11. package/dist/asn1/time.js +55 -1
  12. package/dist/asn1/types.d.ts +100 -16
  13. package/dist/asn1/types.js +47 -6
  14. package/dist/cms/errors.d.ts +12 -2
  15. package/dist/cms/errors.js +7 -1
  16. package/dist/cms/index.d.ts +5 -0
  17. package/dist/cms/index.js +5 -0
  18. package/dist/cms/oids.d.ts +37 -7
  19. package/dist/cms/oids.js +37 -7
  20. package/dist/cms/parse.d.ts +155 -13
  21. package/dist/cms/parse.js +98 -4
  22. package/dist/cms/sign.d.ts +80 -10
  23. package/dist/cms/sign.js +54 -2
  24. package/dist/cms/verify.d.ts +84 -9
  25. package/dist/cms/verify.js +54 -5
  26. package/dist/common/hybrid.d.ts +25 -0
  27. package/dist/common/hybrid.js +25 -0
  28. package/dist/common/sealed.d.ts +119 -15
  29. package/dist/common/sealed.js +67 -9
  30. package/dist/esbuild-plugin.d.ts +74 -5
  31. package/dist/esbuild-plugin.js +69 -4
  32. package/dist/index.d.ts +19 -0
  33. package/dist/index.js +22 -0
  34. package/dist/pem/asn1.d.ts +13 -0
  35. package/dist/pem/asn1.js +13 -0
  36. package/dist/pem/index.d.ts +2 -0
  37. package/dist/pem/index.js +2 -0
  38. package/dist/pem/pkcs8.d.ts +64 -8
  39. package/dist/pem/pkcs8.js +66 -6
  40. package/dist/pem/sm2.d.ts +76 -4
  41. package/dist/pem/sm2.js +169 -12
  42. package/dist/pem/sm9.d.ts +42 -2
  43. package/dist/pem/sm9.js +42 -2
  44. package/dist/runtime/base64.core.d.ts +25 -1
  45. package/dist/runtime/base64.core.js +31 -1
  46. package/dist/runtime/convert.d.ts +70 -7
  47. package/dist/runtime/convert.js +129 -9
  48. package/dist/runtime/errors.d.ts +64 -8
  49. package/dist/runtime/errors.js +64 -8
  50. package/dist/runtime/index.d.ts +5 -0
  51. package/dist/runtime/index.js +5 -0
  52. package/dist/runtime/loadWasm.browser.d.ts +33 -0
  53. package/dist/runtime/loadWasm.browser.js +46 -0
  54. package/dist/runtime/loadWasm.core.d.ts +59 -3
  55. package/dist/runtime/loadWasm.core.js +53 -3
  56. package/dist/runtime/loadWasm.d.ts +44 -0
  57. package/dist/runtime/loadWasm.js +79 -4
  58. package/dist/runtime/random.browser.d.ts +24 -0
  59. package/dist/runtime/random.browser.js +31 -1
  60. package/dist/runtime/random.core.d.ts +21 -0
  61. package/dist/runtime/random.core.js +27 -0
  62. package/dist/runtime/random.d.ts +28 -0
  63. package/dist/runtime/random.js +40 -1
  64. package/dist/sm2/exchange.d.ts +132 -16
  65. package/dist/sm2/exchange.js +120 -9
  66. package/dist/sm2/hybrid.d.ts +65 -3
  67. package/dist/sm2/hybrid.js +53 -1
  68. package/dist/sm2/index.d.ts +260 -21
  69. package/dist/sm2/index.js +346 -23
  70. package/dist/sm2/kem.d.ts +62 -5
  71. package/dist/sm2/kem.js +37 -2
  72. package/dist/sm2/keyInput.d.ts +36 -3
  73. package/dist/sm2/keyInput.js +36 -3
  74. package/dist/sm3/index.d.ts +30 -0
  75. package/dist/sm3/index.js +55 -1
  76. package/dist/sm4/index.d.ts +125 -17
  77. package/dist/sm4/index.js +201 -14
  78. package/dist/sm9/core.d.ts +58 -8
  79. package/dist/sm9/core.js +36 -5
  80. package/dist/sm9/hybrid.d.ts +66 -3
  81. package/dist/sm9/hybrid.js +46 -1
  82. package/dist/sm9/index.d.ts +265 -19
  83. package/dist/sm9/index.js +175 -5
  84. package/dist/sm9/input.d.ts +37 -2
  85. package/dist/sm9/input.js +50 -1
  86. package/dist/sm9/kem.d.ts +57 -4
  87. package/dist/sm9/kem.js +47 -1
  88. package/dist/webcrypto/algorithms.d.ts +58 -12
  89. package/dist/webcrypto/algorithms.js +58 -10
  90. package/dist/webcrypto/cryptoKey.d.ts +81 -15
  91. package/dist/webcrypto/cryptoKey.js +69 -11
  92. package/dist/webcrypto/errors.d.ts +29 -5
  93. package/dist/webcrypto/errors.js +29 -5
  94. package/dist/webcrypto/index.d.ts +10 -0
  95. package/dist/webcrypto/index.js +10 -0
  96. package/dist/webcrypto/subtle.d.ts +53 -3
  97. package/dist/webcrypto/subtle.js +69 -1
  98. package/dist/x509/encode.d.ts +86 -16
  99. package/dist/x509/encode.js +89 -16
  100. package/dist/x509/errors.d.ts +16 -1
  101. package/dist/x509/errors.js +16 -1
  102. package/dist/x509/extensions.d.ts +46 -7
  103. package/dist/x509/extensions.js +67 -9
  104. package/dist/x509/index.d.ts +7 -0
  105. package/dist/x509/index.js +19 -0
  106. package/dist/x509/ip.d.ts +9 -0
  107. package/dist/x509/ip.js +21 -0
  108. package/dist/x509/issue.d.ts +45 -2
  109. package/dist/x509/issue.js +107 -0
  110. package/dist/x509/oids.d.ts +41 -7
  111. package/dist/x509/oids.js +58 -7
  112. package/dist/x509/parse.d.ts +21 -0
  113. package/dist/x509/parse.js +115 -1
  114. package/dist/x509/sha1.d.ts +12 -1
  115. package/dist/x509/sha1.js +18 -1
  116. package/dist/x509/sha256.d.ts +12 -1
  117. package/dist/x509/sha256.js +31 -1
  118. package/dist/x509/sig.d.ts +15 -0
  119. package/dist/x509/sig.js +28 -1
  120. package/dist/x509/types.d.ts +312 -57
  121. package/dist/x509/types.js +6 -0
  122. package/dist/x509/verify.d.ts +51 -4
  123. package/dist/x509/verify.js +42 -3
  124. package/dist/zuc/index.d.ts +128 -10
  125. package/dist/zuc/index.js +136 -7
  126. package/package.json +53 -36
@@ -8,12 +8,29 @@
8
8
  * - BOOLEAN TRUE 编码为 0xFF;
9
9
  * - INTEGER 使用最小补码编码;
10
10
  * - 输出始终是 definite-length(BER indefinite 只在解析侧接受)。
11
+ *
12
+ * ASN.1 DER encoder and builders.
13
+ *
14
+ * Rules:
15
+ * - `encode()` rebuilds the leading byte from `cls + constructed + tag` (fixing the
16
+ * legacy implementation dropping the constructed bit) and recurses into children
17
+ * of constructed nodes;
18
+ * - SET OF is sorted by encoded bytes (a DER requirement);
19
+ * - BOOLEAN TRUE is encoded as 0xFF;
20
+ * - INTEGER uses minimal two's-complement encoding;
21
+ * - output is always definite-length (BER indefinite is only accepted when parsing).
11
22
  */
12
23
  import { encodeOid } from './oid.js';
13
24
  import { encodeGeneralizedTime, encodeTime, encodeUtcTime } from './time.js';
14
25
  import { Asn1Class, Asn1Error, UniversalTag } from './types.js';
15
26
  // ----------------- 基础编码 -----------------
16
- /** 编码单个节点为 DER 字节。 */
27
+ //
28
+ // ----------------- Basic encoding -----------------
29
+ /**
30
+ * 编码单个节点为 DER 字节。
31
+ *
32
+ * Encodes a single node to DER bytes.
33
+ */
17
34
  export function encode(node) {
18
35
  const constructed = node.children !== undefined ? true : node.constructed;
19
36
  const value = constructed
@@ -28,9 +45,17 @@ export function encode(node) {
28
45
  * `encode` 的旧名(兼容 `src/pem/asn1.ts` 的历史导出)。
29
46
  *
30
47
  * @deprecated 使用 `encode`。
48
+ *
49
+ * Legacy alias of `encode` (kept for the historical exports of `src/pem/asn1.ts`).
50
+ *
51
+ * @deprecated Use `encode`.
31
52
  */
32
53
  export const encodeDer = encode;
33
- /** 编码 tag 首字节(含高 tag number 的 base128 展开)。 */
54
+ /**
55
+ * 编码 tag 首字节(含高 tag number 的 base128 展开)。
56
+ *
57
+ * Encodes the tag's leading byte (including base128 expansion of high tag numbers).
58
+ */
34
59
  export function encodeTag(cls, constructed, tag) {
35
60
  if (!Number.isInteger(tag) || tag < 0) {
36
61
  throw new Asn1Error(`encodeTag: invalid tag ${tag}`);
@@ -50,7 +75,11 @@ export function encodeTag(cls, constructed, tag) {
50
75
  out.push(...groups);
51
76
  return new Uint8Array(out);
52
77
  }
53
- /** 编码 definite-length。 */
78
+ /**
79
+ * 编码 definite-length。
80
+ *
81
+ * Encodes a definite length.
82
+ */
54
83
  export function encodeLength(length) {
55
84
  if (!Number.isInteger(length) || length < 0) {
56
85
  throw new Asn1Error(`encodeLength: bad length ${length}`);
@@ -66,15 +95,29 @@ export function encodeLength(length) {
66
95
  return new Uint8Array([0x80 | bytes.length, ...bytes]);
67
96
  }
68
97
  // ----------------- 构造器 -----------------
69
- /** 构造 SEQUENCE。 */
98
+ //
99
+ // ----------------- Builders -----------------
100
+ /**
101
+ * 构造 SEQUENCE。
102
+ *
103
+ * Builds a SEQUENCE.
104
+ */
70
105
  export function seq(children) {
71
106
  return makeConstructed(Asn1Class.Universal, UniversalTag.Sequence, children);
72
107
  }
73
- /** 构造 SET(保持给定顺序;ASN.1 SET 的排序语义由调用方负责)。 */
108
+ /**
109
+ * 构造 SET(保持给定顺序;ASN.1 SET 的排序语义由调用方负责)。
110
+ *
111
+ * Builds a SET, keeping the given order; ordering semantics are the caller's job.
112
+ */
74
113
  export function set(children) {
75
114
  return makeConstructed(Asn1Class.Universal, UniversalTag.Set, children);
76
115
  }
77
- /** 构造 SET OF(按 DER 编码字节排序)。 */
116
+ /**
117
+ * 构造 SET OF(按 DER 编码字节排序)。
118
+ *
119
+ * Builds a SET OF, sorted by encoded DER bytes.
120
+ */
78
121
  export function setOf(children) {
79
122
  const sorted = children
80
123
  .map((node) => ({ node, bytes: encode(node) }))
@@ -82,7 +125,11 @@ export function setOf(children) {
82
125
  .map((entry) => entry.node);
83
126
  return makeConstructed(Asn1Class.Universal, UniversalTag.Set, sorted);
84
127
  }
85
- /** 构造 `[tag] EXPLICIT` 包装。 */
128
+ /**
129
+ * 构造 `[tag] EXPLICIT` 包装。
130
+ *
131
+ * Builds a `[tag] EXPLICIT` wrapper.
132
+ */
86
133
  export function explicit(tag, inner) {
87
134
  const value = encode(inner);
88
135
  return {
@@ -102,6 +149,9 @@ export function explicit(tag, inner) {
102
149
  }
103
150
  /**
104
151
  * 构造 `[tag] IMPLICIT` 包装:只替换外层标签,内容保持不变。
152
+ *
153
+ * Builds a `[tag] IMPLICIT` wrapper: only the outer tag is replaced, the content is
154
+ * kept unchanged.
105
155
  */
106
156
  export function implicit(tag, inner, cls = Asn1Class.ContextSpecific) {
107
157
  const constructed = inner.children !== undefined ? true : inner.constructed;
@@ -117,7 +167,11 @@ export function implicit(tag, inner, cls = Asn1Class.ContextSpecific) {
117
167
  raw: concat([encodeTag(cls, constructed, tag), encodeLength(value.length), value]),
118
168
  };
119
169
  }
120
- /** 构造 BIT STRING。`unusedBits` 为末尾未使用位数(0..7)。 */
170
+ /**
171
+ * 构造 BIT STRING。`unusedBits` 为末尾未使用位数(0..7)。
172
+ *
173
+ * Builds a BIT STRING; `unusedBits` is the number of unused trailing bits (0..7).
174
+ */
121
175
  export function bitString(bytes, unusedBits = 0) {
122
176
  if (!Number.isInteger(unusedBits) || unusedBits < 0 || unusedBits > 7) {
123
177
  throw new RangeError(`bitString: unusedBits must be 0..7, got ${unusedBits}`);
@@ -127,41 +181,73 @@ export function bitString(bytes, unusedBits = 0) {
127
181
  value.set(bytes, 1);
128
182
  return makePrimitive(UniversalTag.BitString, value);
129
183
  }
130
- /** 构造 OCTET STRING。 */
184
+ /**
185
+ * 构造 OCTET STRING。
186
+ *
187
+ * Builds an OCTET STRING.
188
+ */
131
189
  export function octetString(bytes) {
132
190
  return makePrimitive(UniversalTag.OctetString, bytes);
133
191
  }
134
- /** 构造 BOOLEAN。 */
192
+ /**
193
+ * 构造 BOOLEAN。
194
+ *
195
+ * Builds a BOOLEAN.
196
+ */
135
197
  export function boolean(value) {
136
198
  return makePrimitive(UniversalTag.Boolean, new Uint8Array([value ? 0xff : 0x00]));
137
199
  }
138
- /** 构造 NULL。 */
200
+ /**
201
+ * 构造 NULL。
202
+ *
203
+ * Builds a NULL.
204
+ */
139
205
  export function nullValue() {
140
206
  return makePrimitive(UniversalTag.Null, new Uint8Array(0));
141
207
  }
142
- /** 构造 INTEGER(最小补码编码)。 */
208
+ /**
209
+ * 构造 INTEGER(最小补码编码)。
210
+ *
211
+ * Builds an INTEGER (minimal two's-complement encoding).
212
+ */
143
213
  export function integer(value) {
144
214
  const v = typeof value === 'number' ? BigInt(value) : value;
145
215
  if (typeof v !== 'bigint')
146
216
  throw new Asn1Error('integer: value must be bigint or number');
147
217
  return makePrimitive(UniversalTag.Integer, encodeIntegerValue(v));
148
218
  }
149
- /** 构造 OBJECT IDENTIFIER。 */
219
+ /**
220
+ * 构造 OBJECT IDENTIFIER。
221
+ *
222
+ * Builds an OBJECT IDENTIFIER.
223
+ */
150
224
  export function oid(value) {
151
225
  return makePrimitive(UniversalTag.ObjectIdentifier, encodeOid(value));
152
226
  }
153
- /** 构造 UTF8String。 */
227
+ /**
228
+ * 构造 UTF8String。
229
+ *
230
+ * Builds a UTF8String.
231
+ */
154
232
  export function utf8String(value) {
155
233
  return makePrimitive(UniversalTag.Utf8String, new TextEncoder().encode(value));
156
234
  }
157
- /** 构造 PrintableString(仅允许 A-Z a-z 0-9 与 `'()+,-./:=?` 和空格)。 */
235
+ /**
236
+ * 构造 PrintableString(仅允许 A-Z a-z 0-9 与 `'()+,-./:=?` 和空格)。
237
+ *
238
+ * Builds a PrintableString (only A-Z a-z 0-9 and `'()+,-./:=?` plus space allowed).
239
+ */
158
240
  export function printableString(value) {
159
241
  if (!/^[A-Za-z0-9 '()+,\-./:=?]*$/.test(value)) {
160
242
  throw new Asn1Error(`printableString: unsupported character in "${value}"`);
161
243
  }
162
244
  return makePrimitive(UniversalTag.PrintableString, asciiBytes(value));
163
245
  }
164
- /** 构造 IA5String(仅 ASCII)。 */
246
+ /**
247
+ * 构造 IA5String(仅 ASCII)。
248
+ *
249
+ * Builds an IA5String (ASCII only).
250
+ */
165
251
  export function ia5String(value) {
166
252
  for (let i = 0; i < value.length; i++) {
167
253
  if (value.charCodeAt(i) > 0x7f) {
@@ -170,19 +256,38 @@ export function ia5String(value) {
170
256
  }
171
257
  return makePrimitive(UniversalTag.Ia5String, asciiBytes(value));
172
258
  }
173
- /** 构造 UTCTime(1950–2049)。 */
259
+ /**
260
+ * 构造 UTCTime(1950–2049)。
261
+ *
262
+ * Builds a UTCTime (years 1950–2049).
263
+ */
174
264
  export function utcTime(date) {
175
265
  return makePrimitive(UniversalTag.UtcTime, asciiBytes(encodeUtcTime(date)));
176
266
  }
177
- /** 构造 GeneralizedTime。 */
267
+ /**
268
+ * 构造 GeneralizedTime。
269
+ *
270
+ * Builds a GeneralizedTime.
271
+ */
178
272
  export function generalizedTime(date) {
179
273
  return makePrimitive(UniversalTag.GeneralizedTime, asciiBytes(encodeGeneralizedTime(date)));
180
274
  }
181
- /** 按 RFC 5280 自动选择 UTCTime / GeneralizedTime。 */
275
+ /**
276
+ * 按 RFC 5280 自动选择 UTCTime / GeneralizedTime。
277
+ *
278
+ * Picks UTCTime / GeneralizedTime automatically as RFC 5280 requires.
279
+ */
182
280
  export function time(date) {
183
281
  return makePrimitive(isUtcYear(date) ? UniversalTag.UtcTime : UniversalTag.GeneralizedTime, asciiBytes(encodeTime(date)));
184
282
  }
185
283
  // ----------------- 内部 -----------------
284
+ //
285
+ // ----------------- Internals -----------------
286
+ /**
287
+ * 构造 UNIVERSAL primitive 节点。
288
+ *
289
+ * Builds a UNIVERSAL primitive node.
290
+ */
186
291
  function makePrimitive(tag, value) {
187
292
  return {
188
293
  cls: Asn1Class.Universal,
@@ -194,6 +299,12 @@ function makePrimitive(tag, value) {
194
299
  raw: concat([encodeTag(Asn1Class.Universal, false, tag), encodeLength(value.length), value]),
195
300
  };
196
301
  }
302
+ /**
303
+ * 构造 UNIVERSAL constructed 节点(value 由子节点编码拼接而成)。
304
+ *
305
+ * Builds a UNIVERSAL constructed node whose value is the concatenated encoded
306
+ * children.
307
+ */
197
308
  function makeConstructed(cls, tag, children) {
198
309
  const value = concat(children.map((child) => encode(child)));
199
310
  return {
@@ -207,6 +318,11 @@ function makeConstructed(cls, tag, children) {
207
318
  raw: concat([encodeTag(cls, true, tag), encodeLength(value.length), value]),
208
319
  };
209
320
  }
321
+ /**
322
+ * 判断日期年份是否落在 UTCTime 适用范围(1950–2049)。
323
+ *
324
+ * Whether the year falls in the UTCTime range (1950–2049).
325
+ */
210
326
  function isUtcYear(date) {
211
327
  if (!(date instanceof Date) || Number.isNaN(date.getTime()))
212
328
  return false;
@@ -219,6 +335,13 @@ function isUtcYear(date) {
219
335
  * - 0 → `00`;
220
336
  * - 正数:最高位为 1 时前置 `00`;
221
337
  * - 负数:选择最少字节数 n 使 `-2^(8n-1) <= v`,按 2^(8n) 取模。
338
+ *
339
+ * Minimal two's-complement INTEGER encoding.
340
+ *
341
+ * - 0 → `00`;
342
+ * - positive: prepend `00` when the top bit would otherwise be set;
343
+ * - negative: pick the fewest bytes n such that `-2^(8n-1) <= v`, then reduce modulo
344
+ * 2^(8n).
222
345
  */
223
346
  export function encodeIntegerValue(v) {
224
347
  if (v === 0n)
@@ -246,12 +369,23 @@ export function encodeIntegerValue(v) {
246
369
  }
247
370
  return out;
248
371
  }
372
+ /**
373
+ * 字符串 → ASCII 字节(高于 0x7f 的码位被截断,调用方负责预先校验)。
374
+ *
375
+ * String to ASCII bytes; code points above 0x7f are truncated, so callers must
376
+ * validate beforehand.
377
+ */
249
378
  function asciiBytes(text) {
250
379
  const out = new Uint8Array(text.length);
251
380
  for (let i = 0; i < text.length; i++)
252
381
  out[i] = text.charCodeAt(i) & 0x7f;
253
382
  return out;
254
383
  }
384
+ /**
385
+ * 字节字典序比较(DER SET OF 排序依据)。
386
+ *
387
+ * Lexicographic byte comparison, the ordering rule for DER SET OF.
388
+ */
255
389
  function compareBytes(a, b) {
256
390
  const n = Math.min(a.length, b.length);
257
391
  for (let i = 0; i < n; i++) {
@@ -261,6 +395,11 @@ function compareBytes(a, b) {
261
395
  }
262
396
  return a.length - b.length;
263
397
  }
398
+ /**
399
+ * 拼多个字节数组为一个新数组。
400
+ *
401
+ * Concatenates byte arrays into a new array.
402
+ */
264
403
  function concat(parts) {
265
404
  let total = 0;
266
405
  for (const p of parts)
@@ -3,6 +3,12 @@
3
3
  *
4
4
  * **不进入主入口导出**(spec Anti-Goal:不公开底层 DER/大数接口)。
5
5
  * `src/pem/asn1.ts` 仍按旧符号名 re-export 本层,供 PEM/PKCS#8 代码与测试使用。
6
+ *
7
+ * Internal ASN.1 layer barrel.
8
+ *
9
+ * **Not exported from the main entry** (spec anti-goal: the low-level DER/big-number
10
+ * interfaces stay private). `src/pem/asn1.ts` still re-exports this layer under the
11
+ * legacy symbol names for the PEM/PKCS#8 code and the tests.
6
12
  */
7
13
  export * from './decode.js';
8
14
  export * from './encode.js';
@@ -3,6 +3,12 @@
3
3
  *
4
4
  * **不进入主入口导出**(spec Anti-Goal:不公开底层 DER/大数接口)。
5
5
  * `src/pem/asn1.ts` 仍按旧符号名 re-export 本层,供 PEM/PKCS#8 代码与测试使用。
6
+ *
7
+ * Internal ASN.1 layer barrel.
8
+ *
9
+ * **Not exported from the main entry** (spec anti-goal: the low-level DER/big-number
10
+ * interfaces stay private). `src/pem/asn1.ts` still re-exports this layer under the
11
+ * legacy symbol names for the PEM/PKCS#8 code and the tests.
6
12
  */
7
13
  export * from './decode.js';
8
14
  export * from './encode.js';
@@ -6,17 +6,35 @@
6
6
  * 长组件不会溢出);
7
7
  * - 首个子标识符也走 base128 编码,支持 `2.999` 这类第二组件 ≥ 40 的 OID;
8
8
  * - 解码时拒绝截断、空输入与非最小(前导 0x80)编码。
9
+ *
10
+ * OBJECT IDENTIFIER encoding and decoding.
11
+ *
12
+ * Differences from the legacy implementation:
13
+ * - Accumulates in `bigint`, so 32-bit bitwise limits no longer apply (long arcs such
14
+ * as `1.2.840.113549...` cannot overflow);
15
+ * - The first subidentifier also goes through base128, so OIDs whose second arc is
16
+ * ≥ 40 (such as `2.999`) are supported;
17
+ * - Decoding rejects truncation, empty input and non-minimal (leading 0x80) encodings.
9
18
  */
10
19
  /**
11
20
  * 点分 OID → 内容字节(不含 tag 与 length)。
12
21
  *
13
22
  * @param oid 形如 `"1.2.156.10197.1.100"`。
14
23
  * @throws Asn1Error 格式非法或组件越界。
24
+ *
25
+ * Dotted OID → content bytes (without tag and length).
26
+ *
27
+ * @param oid Something like `"1.2.156.10197.1.100"`.
28
+ * @throws Asn1Error On malformed syntax or out-of-range components.
15
29
  */
16
30
  export declare function encodeOid(oid: string): Uint8Array;
17
31
  /**
18
32
  * 内容字节 → 点分 OID。
19
33
  *
20
34
  * @throws Asn1Error 空输入、截断或非法 base128 编码。
35
+ *
36
+ * Content bytes → dotted OID.
37
+ *
38
+ * @throws Asn1Error On empty input, truncation, or an invalid base128 encoding.
21
39
  */
22
40
  export declare function decodeOid(bytes: Uint8Array): string;
package/dist/asn1/oid.js CHANGED
@@ -6,6 +6,15 @@
6
6
  * 长组件不会溢出);
7
7
  * - 首个子标识符也走 base128 编码,支持 `2.999` 这类第二组件 ≥ 40 的 OID;
8
8
  * - 解码时拒绝截断、空输入与非最小(前导 0x80)编码。
9
+ *
10
+ * OBJECT IDENTIFIER encoding and decoding.
11
+ *
12
+ * Differences from the legacy implementation:
13
+ * - Accumulates in `bigint`, so 32-bit bitwise limits no longer apply (long arcs such
14
+ * as `1.2.840.113549...` cannot overflow);
15
+ * - The first subidentifier also goes through base128, so OIDs whose second arc is
16
+ * ≥ 40 (such as `2.999`) are supported;
17
+ * - Decoding rejects truncation, empty input and non-minimal (leading 0x80) encodings.
9
18
  */
10
19
  import { Asn1Error } from './types.js';
11
20
  /**
@@ -13,6 +22,11 @@ import { Asn1Error } from './types.js';
13
22
  *
14
23
  * @param oid 形如 `"1.2.156.10197.1.100"`。
15
24
  * @throws Asn1Error 格式非法或组件越界。
25
+ *
26
+ * Dotted OID → content bytes (without tag and length).
27
+ *
28
+ * @param oid Something like `"1.2.156.10197.1.100"`.
29
+ * @throws Asn1Error On malformed syntax or out-of-range components.
16
30
  */
17
31
  export function encodeOid(oid) {
18
32
  const parts = parseOidComponents(oid);
@@ -27,6 +41,10 @@ export function encodeOid(oid) {
27
41
  * 内容字节 → 点分 OID。
28
42
  *
29
43
  * @throws Asn1Error 空输入、截断或非法 base128 编码。
44
+ *
45
+ * Content bytes → dotted OID.
46
+ *
47
+ * @throws Asn1Error On empty input, truncation, or an invalid base128 encoding.
30
48
  */
31
49
  export function decodeOid(bytes) {
32
50
  if (bytes.length === 0)
@@ -37,6 +55,8 @@ export function decodeOid(bytes) {
37
55
  for (let i = 0; i < bytes.length; i++) {
38
56
  const octet = bytes[i] ?? 0;
39
57
  // 每个子标识符的编码不得以 0x80 开头(非最小编码)。
58
+ //
59
+ // A subidentifier's encoding must not start with 0x80 (non-minimal encoding).
40
60
  if (!pending && octet === 0x80) {
41
61
  throw new Asn1Error('decodeOid: non-minimal base128 encoding');
42
62
  }
@@ -67,6 +87,11 @@ export function decodeOid(bytes) {
67
87
  const parts = [a, b, ...values.slice(1)];
68
88
  return parts.map((v) => v.toString(10)).join('.');
69
89
  }
90
+ /**
91
+ * 校验并拆分点分 OID(每个组件为无符号十进制整数)。
92
+ *
93
+ * Validates and splits a dotted OID (each component is an unsigned decimal integer).
94
+ */
70
95
  function parseOidComponents(oid) {
71
96
  if (typeof oid !== 'string' || oid.length === 0) {
72
97
  throw new Asn1Error(`encodeOid: bad oid "${String(oid)}"`);
@@ -90,7 +115,11 @@ function parseOidComponents(oid) {
90
115
  }
91
116
  return parts;
92
117
  }
93
- /** 无符号 bigint → base128 字节(高位 bit 为续行标志)。 */
118
+ /**
119
+ * 无符号 bigint → base128 字节(高位 bit 为续行标志)。
120
+ *
121
+ * Unsigned bigint → base128 bytes (the high bit marks a continuation).
122
+ */
94
123
  function encodeBase128(value) {
95
124
  if (value < 0n)
96
125
  throw new Asn1Error(`encodeBase128: negative value ${value}`);
@@ -8,21 +8,43 @@
8
8
  *
9
9
  * 解析刻意宽松(接受无秒、无时区、GeneralizedTime 的小数秒),因为真实现场
10
10
  * 存在非规范编码;编码始终输出规范形式。
11
+ *
12
+ * X.509 time encoding/parsing (UTCTime / GeneralizedTime).
13
+ *
14
+ * Rules (RFC 5280):
15
+ * - 1950–2049 use UTCTime (`YYMMDDHHMMSSZ`);
16
+ * - Other years use GeneralizedTime (`YYYYMMDDHHMMSSZ`);
17
+ * - Certificate time has second precision: milliseconds are truncated when parsing,
18
+ * keeping parse → encode round-trips stable.
19
+ *
20
+ * Parsing is deliberately lenient (missing seconds, missing timezone, GeneralizedTime
21
+ * fractional seconds) because non-canonical encodings exist in the wild; encoding
22
+ * always emits the canonical form.
11
23
  */
12
24
  /**
13
25
  * 编码 UTCTime(仅接受 1950–2049 年)。
14
26
  *
15
27
  * @throws RangeError 日期无效或年份越界。
28
+ *
29
+ * Encodes a UTCTime (years 1950–2049 only).
30
+ *
31
+ * @throws RangeError When the Date is invalid or the year is out of range.
16
32
  */
17
33
  export declare function encodeUtcTime(date: Date): string;
18
34
  /**
19
35
  * 编码 GeneralizedTime。
20
36
  *
21
37
  * @throws RangeError 日期无效。
38
+ *
39
+ * Encodes a GeneralizedTime.
40
+ *
41
+ * @throws RangeError When the Date is invalid.
22
42
  */
23
43
  export declare function encodeGeneralizedTime(date: Date): string;
24
44
  /**
25
45
  * 按 RFC 5280 自动选择 UTCTime(1950–2049)或 GeneralizedTime。
46
+ *
47
+ * Picks UTCTime (1950–2049) or GeneralizedTime automatically as RFC 5280 requires.
26
48
  */
27
49
  export declare function encodeTime(date: Date): string;
28
50
  /**
@@ -35,5 +57,15 @@ export declare function encodeTime(date: Date): string;
35
57
  *
36
58
  * @returns 毫秒为 0 的 `Date`。
37
59
  * @throws Asn1Error 格式或日期分量非法。
60
+ *
61
+ * Parses a UTCTime or GeneralizedTime string.
62
+ *
63
+ * Accepts:
64
+ * - `YYMMDDHHMMSSZ` / `YYMMDDHHMMZ` (UTCTime; 50–99 → 1950–1999, 00–49 → 2000–2049);
65
+ * - `YYYYMMDDHHMMSSZ` / `YYYYMMDDHHMMZ` / `YYYYMMDDHHMMSS.sssZ` (GeneralizedTime);
66
+ * - an optional `+HHMM` / `-HHMM` offset on the time part; a missing timezone means UTC.
67
+ *
68
+ * @returns A `Date` whose milliseconds are 0.
69
+ * @throws Asn1Error On illegal syntax or date components.
38
70
  */
39
71
  export declare function parseTime(text: string): Date;
package/dist/asn1/time.js CHANGED
@@ -8,12 +8,28 @@
8
8
  *
9
9
  * 解析刻意宽松(接受无秒、无时区、GeneralizedTime 的小数秒),因为真实现场
10
10
  * 存在非规范编码;编码始终输出规范形式。
11
+ *
12
+ * X.509 time encoding/parsing (UTCTime / GeneralizedTime).
13
+ *
14
+ * Rules (RFC 5280):
15
+ * - 1950–2049 use UTCTime (`YYMMDDHHMMSSZ`);
16
+ * - Other years use GeneralizedTime (`YYYYMMDDHHMMSSZ`);
17
+ * - Certificate time has second precision: milliseconds are truncated when parsing,
18
+ * keeping parse → encode round-trips stable.
19
+ *
20
+ * Parsing is deliberately lenient (missing seconds, missing timezone, GeneralizedTime
21
+ * fractional seconds) because non-canonical encodings exist in the wild; encoding
22
+ * always emits the canonical form.
11
23
  */
12
24
  import { Asn1Error } from './types.js';
13
25
  /**
14
26
  * 编码 UTCTime(仅接受 1950–2049 年)。
15
27
  *
16
28
  * @throws RangeError 日期无效或年份越界。
29
+ *
30
+ * Encodes a UTCTime (years 1950–2049 only).
31
+ *
32
+ * @throws RangeError When the Date is invalid or the year is out of range.
17
33
  */
18
34
  export function encodeUtcTime(date) {
19
35
  const { year, month, day, hour, minute, second } = utcParts(date, 'encodeUtcTime');
@@ -27,6 +43,10 @@ export function encodeUtcTime(date) {
27
43
  * 编码 GeneralizedTime。
28
44
  *
29
45
  * @throws RangeError 日期无效。
46
+ *
47
+ * Encodes a GeneralizedTime.
48
+ *
49
+ * @throws RangeError When the Date is invalid.
30
50
  */
31
51
  export function encodeGeneralizedTime(date) {
32
52
  const { year, month, day, hour, minute, second } = utcParts(date, 'encodeGeneralizedTime');
@@ -34,6 +54,8 @@ export function encodeGeneralizedTime(date) {
34
54
  }
35
55
  /**
36
56
  * 按 RFC 5280 自动选择 UTCTime(1950–2049)或 GeneralizedTime。
57
+ *
58
+ * Picks UTCTime (1950–2049) or GeneralizedTime automatically as RFC 5280 requires.
37
59
  */
38
60
  export function encodeTime(date) {
39
61
  const year = utcParts(date, 'encodeTime').year;
@@ -49,6 +71,16 @@ export function encodeTime(date) {
49
71
  *
50
72
  * @returns 毫秒为 0 的 `Date`。
51
73
  * @throws Asn1Error 格式或日期分量非法。
74
+ *
75
+ * Parses a UTCTime or GeneralizedTime string.
76
+ *
77
+ * Accepts:
78
+ * - `YYMMDDHHMMSSZ` / `YYMMDDHHMMZ` (UTCTime; 50–99 → 1950–1999, 00–49 → 2000–2049);
79
+ * - `YYYYMMDDHHMMSSZ` / `YYYYMMDDHHMMZ` / `YYYYMMDDHHMMSS.sssZ` (GeneralizedTime);
80
+ * - an optional `+HHMM` / `-HHMM` offset on the time part; a missing timezone means UTC.
81
+ *
82
+ * @returns A `Date` whose milliseconds are 0.
83
+ * @throws Asn1Error On illegal syntax or date components.
52
84
  */
53
85
  export function parseTime(text) {
54
86
  const s = text.trim();
@@ -74,6 +106,9 @@ export function parseTime(text) {
74
106
  }
75
107
  const localMs = Date.UTC(year, month - 1, day, hour, minute, second);
76
108
  // 先在「输入的本地分量」上校验日期合法性,再应用时区偏移。
109
+ //
110
+ // Validate the date against the input's local components first, then apply the
111
+ // timezone offset.
77
112
  const local = new Date(localMs);
78
113
  if (Number.isNaN(local.getTime()) ||
79
114
  local.getUTCFullYear() !== year ||
@@ -86,10 +121,19 @@ export function parseTime(text) {
86
121
  }
87
122
  return new Date(localMs - offsetMinutes * 60_000);
88
123
  }
89
- /** UTCTime 两位年份展开。 */
124
+ /**
125
+ * UTCTime 两位年份展开。
126
+ *
127
+ * Expands a two-digit UTCTime year.
128
+ */
90
129
  function utcYear(yy) {
91
130
  return yy >= 50 ? 1900 + yy : 2000 + yy;
92
131
  }
132
+ /**
133
+ * 提取日期的 UTC 分量并校验日期有效性。
134
+ *
135
+ * Extracts the UTC components of a Date and validates it.
136
+ */
93
137
  function utcParts(date, where) {
94
138
  if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
95
139
  throw new RangeError(`${where}: invalid Date`);
@@ -103,9 +147,19 @@ function utcParts(date, where) {
103
147
  second: date.getUTCSeconds(),
104
148
  };
105
149
  }
150
+ /**
151
+ * 十进制补零到 2 位。
152
+ *
153
+ * Zero-pads a decimal number to 2 digits.
154
+ */
106
155
  function pad2(n) {
107
156
  return n.toString(10).padStart(2, '0');
108
157
  }
158
+ /**
159
+ * 十进制补零到 4 位。
160
+ *
161
+ * Zero-pads a decimal number to 4 digits.
162
+ */
109
163
  function pad4(n) {
110
164
  return n.toString(10).padStart(4, '0');
111
165
  }