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.
- package/README.md +41 -876
- package/dist/asn1/decode.d.ts +103 -12
- package/dist/asn1/decode.js +129 -10
- package/dist/asn1/encode.d.ts +120 -19
- package/dist/asn1/encode.js +158 -19
- package/dist/asn1/index.d.ts +6 -0
- package/dist/asn1/index.js +6 -0
- package/dist/asn1/oid.d.ts +18 -0
- package/dist/asn1/oid.js +30 -1
- package/dist/asn1/time.d.ts +32 -0
- package/dist/asn1/time.js +55 -1
- package/dist/asn1/types.d.ts +100 -16
- package/dist/asn1/types.js +47 -6
- package/dist/cms/errors.d.ts +12 -2
- package/dist/cms/errors.js +7 -1
- package/dist/cms/index.d.ts +5 -0
- package/dist/cms/index.js +5 -0
- package/dist/cms/oids.d.ts +37 -7
- package/dist/cms/oids.js +37 -7
- package/dist/cms/parse.d.ts +155 -13
- package/dist/cms/parse.js +98 -4
- package/dist/cms/sign.d.ts +80 -10
- package/dist/cms/sign.js +54 -2
- package/dist/cms/verify.d.ts +84 -9
- package/dist/cms/verify.js +54 -5
- package/dist/common/hybrid.d.ts +25 -0
- package/dist/common/hybrid.js +25 -0
- package/dist/common/sealed.d.ts +119 -15
- package/dist/common/sealed.js +67 -9
- package/dist/esbuild-plugin.d.ts +74 -5
- package/dist/esbuild-plugin.js +69 -4
- package/dist/index.d.ts +19 -0
- package/dist/index.js +22 -0
- package/dist/pem/asn1.d.ts +13 -0
- package/dist/pem/asn1.js +13 -0
- package/dist/pem/index.d.ts +2 -0
- package/dist/pem/index.js +2 -0
- package/dist/pem/pkcs8.d.ts +64 -8
- package/dist/pem/pkcs8.js +66 -6
- package/dist/pem/sm2.d.ts +76 -4
- package/dist/pem/sm2.js +169 -12
- package/dist/pem/sm9.d.ts +42 -2
- package/dist/pem/sm9.js +42 -2
- package/dist/runtime/base64.core.d.ts +25 -1
- package/dist/runtime/base64.core.js +31 -1
- package/dist/runtime/convert.d.ts +70 -7
- package/dist/runtime/convert.js +129 -9
- package/dist/runtime/errors.d.ts +64 -8
- package/dist/runtime/errors.js +64 -8
- package/dist/runtime/index.d.ts +5 -0
- package/dist/runtime/index.js +5 -0
- package/dist/runtime/loadWasm.browser.d.ts +33 -0
- package/dist/runtime/loadWasm.browser.js +46 -0
- package/dist/runtime/loadWasm.core.d.ts +59 -3
- package/dist/runtime/loadWasm.core.js +53 -3
- package/dist/runtime/loadWasm.d.ts +44 -0
- package/dist/runtime/loadWasm.js +79 -4
- package/dist/runtime/random.browser.d.ts +24 -0
- package/dist/runtime/random.browser.js +31 -1
- package/dist/runtime/random.core.d.ts +21 -0
- package/dist/runtime/random.core.js +27 -0
- package/dist/runtime/random.d.ts +28 -0
- package/dist/runtime/random.js +40 -1
- package/dist/sm2/exchange.d.ts +132 -16
- package/dist/sm2/exchange.js +120 -9
- package/dist/sm2/hybrid.d.ts +65 -3
- package/dist/sm2/hybrid.js +53 -1
- package/dist/sm2/index.d.ts +260 -21
- package/dist/sm2/index.js +346 -23
- package/dist/sm2/kem.d.ts +62 -5
- package/dist/sm2/kem.js +37 -2
- package/dist/sm2/keyInput.d.ts +36 -3
- package/dist/sm2/keyInput.js +36 -3
- package/dist/sm3/index.d.ts +30 -0
- package/dist/sm3/index.js +55 -1
- package/dist/sm4/index.d.ts +125 -17
- package/dist/sm4/index.js +201 -14
- package/dist/sm9/core.d.ts +58 -8
- package/dist/sm9/core.js +36 -5
- package/dist/sm9/hybrid.d.ts +66 -3
- package/dist/sm9/hybrid.js +46 -1
- package/dist/sm9/index.d.ts +265 -19
- package/dist/sm9/index.js +175 -5
- package/dist/sm9/input.d.ts +37 -2
- package/dist/sm9/input.js +50 -1
- package/dist/sm9/kem.d.ts +57 -4
- package/dist/sm9/kem.js +47 -1
- package/dist/webcrypto/algorithms.d.ts +58 -12
- package/dist/webcrypto/algorithms.js +58 -10
- package/dist/webcrypto/cryptoKey.d.ts +81 -15
- package/dist/webcrypto/cryptoKey.js +69 -11
- package/dist/webcrypto/errors.d.ts +29 -5
- package/dist/webcrypto/errors.js +29 -5
- package/dist/webcrypto/index.d.ts +10 -0
- package/dist/webcrypto/index.js +10 -0
- package/dist/webcrypto/subtle.d.ts +53 -3
- package/dist/webcrypto/subtle.js +69 -1
- package/dist/x509/encode.d.ts +86 -16
- package/dist/x509/encode.js +89 -16
- package/dist/x509/errors.d.ts +16 -1
- package/dist/x509/errors.js +16 -1
- package/dist/x509/extensions.d.ts +46 -7
- package/dist/x509/extensions.js +67 -9
- package/dist/x509/index.d.ts +7 -0
- package/dist/x509/index.js +19 -0
- package/dist/x509/ip.d.ts +9 -0
- package/dist/x509/ip.js +21 -0
- package/dist/x509/issue.d.ts +45 -2
- package/dist/x509/issue.js +107 -0
- package/dist/x509/oids.d.ts +41 -7
- package/dist/x509/oids.js +58 -7
- package/dist/x509/parse.d.ts +21 -0
- package/dist/x509/parse.js +115 -1
- package/dist/x509/sha1.d.ts +12 -1
- package/dist/x509/sha1.js +18 -1
- package/dist/x509/sha256.d.ts +12 -1
- package/dist/x509/sha256.js +31 -1
- package/dist/x509/sig.d.ts +15 -0
- package/dist/x509/sig.js +28 -1
- package/dist/x509/types.d.ts +312 -57
- package/dist/x509/types.js +6 -0
- package/dist/x509/verify.d.ts +51 -4
- package/dist/x509/verify.js +42 -3
- package/dist/zuc/index.d.ts +128 -10
- package/dist/zuc/index.js +136 -7
- package/package.json +53 -36
package/dist/asn1/encode.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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)
|
package/dist/asn1/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/asn1/index.js
CHANGED
|
@@ -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';
|
package/dist/asn1/oid.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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}`);
|
package/dist/asn1/time.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
}
|