sm-crypto-wasm 0.3.1 → 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 (127) hide show
  1. package/README.md +62 -834
  2. package/dist/asn1/decode.d.ts +165 -0
  3. package/dist/asn1/decode.js +457 -0
  4. package/dist/asn1/encode.d.ts +169 -0
  5. package/dist/asn1/encode.js +414 -0
  6. package/dist/asn1/index.d.ts +17 -0
  7. package/dist/asn1/index.js +17 -0
  8. package/dist/asn1/oid.d.ts +40 -0
  9. package/dist/asn1/oid.js +136 -0
  10. package/dist/asn1/time.d.ts +71 -0
  11. package/dist/asn1/time.js +165 -0
  12. package/dist/asn1/types.d.ts +160 -0
  13. package/dist/asn1/types.js +112 -0
  14. package/dist/cms/errors.d.ts +23 -0
  15. package/dist/cms/errors.js +17 -0
  16. package/dist/cms/index.d.ts +18 -0
  17. package/dist/cms/index.js +15 -0
  18. package/dist/cms/oids.d.ts +47 -0
  19. package/dist/cms/oids.js +47 -0
  20. package/dist/cms/parse.d.ts +217 -0
  21. package/dist/cms/parse.js +420 -0
  22. package/dist/cms/sign.d.ts +113 -0
  23. package/dist/cms/sign.js +194 -0
  24. package/dist/cms/verify.d.ts +117 -0
  25. package/dist/cms/verify.js +222 -0
  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 +22 -0
  33. package/dist/index.js +25 -0
  34. package/dist/pem/asn1.d.ts +19 -65
  35. package/dist/pem/asn1.js +19 -288
  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 +75 -7
  40. package/dist/pem/sm2.d.ts +90 -2
  41. package/dist/pem/sm2.js +204 -15
  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 +324 -16
  69. package/dist/sm2/index.js +530 -19
  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/sm2/sm2.wasm +0 -0
  75. package/dist/sm3/index.d.ts +30 -0
  76. package/dist/sm3/index.js +55 -1
  77. package/dist/sm4/index.d.ts +125 -17
  78. package/dist/sm4/index.js +201 -14
  79. package/dist/sm9/core.d.ts +58 -8
  80. package/dist/sm9/core.js +36 -5
  81. package/dist/sm9/hybrid.d.ts +66 -3
  82. package/dist/sm9/hybrid.js +46 -1
  83. package/dist/sm9/index.d.ts +265 -19
  84. package/dist/sm9/index.js +175 -5
  85. package/dist/sm9/input.d.ts +37 -2
  86. package/dist/sm9/input.js +50 -1
  87. package/dist/sm9/kem.d.ts +57 -4
  88. package/dist/sm9/kem.js +47 -1
  89. package/dist/webcrypto/algorithms.d.ts +88 -0
  90. package/dist/webcrypto/algorithms.js +168 -0
  91. package/dist/webcrypto/cryptoKey.d.ts +130 -0
  92. package/dist/webcrypto/cryptoKey.js +167 -0
  93. package/dist/webcrypto/errors.d.ts +43 -0
  94. package/dist/webcrypto/errors.js +69 -0
  95. package/dist/webcrypto/index.d.ts +24 -0
  96. package/dist/webcrypto/index.js +21 -0
  97. package/dist/webcrypto/subtle.d.ts +118 -0
  98. package/dist/webcrypto/subtle.js +426 -0
  99. package/dist/x509/encode.d.ts +129 -0
  100. package/dist/x509/encode.js +248 -0
  101. package/dist/x509/errors.d.ts +29 -0
  102. package/dist/x509/errors.js +29 -0
  103. package/dist/x509/extensions.d.ts +66 -0
  104. package/dist/x509/extensions.js +273 -0
  105. package/dist/x509/index.d.ts +21 -0
  106. package/dist/x509/index.js +30 -0
  107. package/dist/x509/ip.d.ts +21 -0
  108. package/dist/x509/ip.js +122 -0
  109. package/dist/x509/issue.d.ts +87 -0
  110. package/dist/x509/issue.js +521 -0
  111. package/dist/x509/oids.d.ts +74 -0
  112. package/dist/x509/oids.js +103 -0
  113. package/dist/x509/parse.d.ts +45 -0
  114. package/dist/x509/parse.js +550 -0
  115. package/dist/x509/sha1.d.ts +20 -0
  116. package/dist/x509/sha1.js +89 -0
  117. package/dist/x509/sha256.d.ts +20 -0
  118. package/dist/x509/sha256.js +114 -0
  119. package/dist/x509/sig.d.ts +35 -0
  120. package/dist/x509/sig.js +104 -0
  121. package/dist/x509/types.d.ts +490 -0
  122. package/dist/x509/types.js +13 -0
  123. package/dist/x509/verify.d.ts +91 -0
  124. package/dist/x509/verify.js +105 -0
  125. package/dist/zuc/index.d.ts +128 -10
  126. package/dist/zuc/index.js +136 -7
  127. package/package.json +57 -28
@@ -0,0 +1,169 @@
1
+ /**
2
+ * ASN.1 DER 编码器与构造器。
3
+ *
4
+ * 规则:
5
+ * - `encode()` 按 `cls + constructed + tag` 重建首字节(修复旧实现丢掉
6
+ * constructed 位的问题),对 constructed 节点递归编码子节点;
7
+ * - SET OF 按编码字节排序(DER 要求);
8
+ * - BOOLEAN TRUE 编码为 0xFF;
9
+ * - INTEGER 使用最小补码编码;
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).
22
+ */
23
+ import { Asn1Class, type Asn1Node } from './types.js';
24
+ /**
25
+ * 编码单个节点为 DER 字节。
26
+ *
27
+ * Encodes a single node to DER bytes.
28
+ */
29
+ export declare function encode(node: Asn1Node): Uint8Array;
30
+ /**
31
+ * `encode` 的旧名(兼容 `src/pem/asn1.ts` 的历史导出)。
32
+ *
33
+ * @deprecated 使用 `encode`。
34
+ *
35
+ * Legacy alias of `encode` (kept for the historical exports of `src/pem/asn1.ts`).
36
+ *
37
+ * @deprecated Use `encode`.
38
+ */
39
+ export declare const encodeDer: typeof encode;
40
+ /**
41
+ * 编码 tag 首字节(含高 tag number 的 base128 展开)。
42
+ *
43
+ * Encodes the tag's leading byte (including base128 expansion of high tag numbers).
44
+ */
45
+ export declare function encodeTag(cls: Asn1Class, constructed: boolean, tag: number): Uint8Array;
46
+ /**
47
+ * 编码 definite-length。
48
+ *
49
+ * Encodes a definite length.
50
+ */
51
+ export declare function encodeLength(length: number): Uint8Array;
52
+ /**
53
+ * 构造 SEQUENCE。
54
+ *
55
+ * Builds a SEQUENCE.
56
+ */
57
+ export declare function seq(children: readonly Asn1Node[]): Asn1Node;
58
+ /**
59
+ * 构造 SET(保持给定顺序;ASN.1 SET 的排序语义由调用方负责)。
60
+ *
61
+ * Builds a SET, keeping the given order; ordering semantics are the caller's job.
62
+ */
63
+ export declare function set(children: readonly Asn1Node[]): Asn1Node;
64
+ /**
65
+ * 构造 SET OF(按 DER 编码字节排序)。
66
+ *
67
+ * Builds a SET OF, sorted by encoded DER bytes.
68
+ */
69
+ export declare function setOf(children: readonly Asn1Node[]): Asn1Node;
70
+ /**
71
+ * 构造 `[tag] EXPLICIT` 包装。
72
+ *
73
+ * Builds a `[tag] EXPLICIT` wrapper.
74
+ */
75
+ export declare function explicit(tag: number, inner: Asn1Node): Asn1Node;
76
+ /**
77
+ * 构造 `[tag] IMPLICIT` 包装:只替换外层标签,内容保持不变。
78
+ *
79
+ * Builds a `[tag] IMPLICIT` wrapper: only the outer tag is replaced, the content is
80
+ * kept unchanged.
81
+ */
82
+ export declare function implicit(tag: number, inner: Asn1Node, cls?: Asn1Class): Asn1Node;
83
+ /**
84
+ * 构造 BIT STRING。`unusedBits` 为末尾未使用位数(0..7)。
85
+ *
86
+ * Builds a BIT STRING; `unusedBits` is the number of unused trailing bits (0..7).
87
+ */
88
+ export declare function bitString(bytes: Uint8Array, unusedBits?: number): Asn1Node;
89
+ /**
90
+ * 构造 OCTET STRING。
91
+ *
92
+ * Builds an OCTET STRING.
93
+ */
94
+ export declare function octetString(bytes: Uint8Array): Asn1Node;
95
+ /**
96
+ * 构造 BOOLEAN。
97
+ *
98
+ * Builds a BOOLEAN.
99
+ */
100
+ export declare function boolean(value: boolean): Asn1Node;
101
+ /**
102
+ * 构造 NULL。
103
+ *
104
+ * Builds a NULL.
105
+ */
106
+ export declare function nullValue(): Asn1Node;
107
+ /**
108
+ * 构造 INTEGER(最小补码编码)。
109
+ *
110
+ * Builds an INTEGER (minimal two's-complement encoding).
111
+ */
112
+ export declare function integer(value: bigint | number): Asn1Node;
113
+ /**
114
+ * 构造 OBJECT IDENTIFIER。
115
+ *
116
+ * Builds an OBJECT IDENTIFIER.
117
+ */
118
+ export declare function oid(value: string): Asn1Node;
119
+ /**
120
+ * 构造 UTF8String。
121
+ *
122
+ * Builds a UTF8String.
123
+ */
124
+ export declare function utf8String(value: string): Asn1Node;
125
+ /**
126
+ * 构造 PrintableString(仅允许 A-Z a-z 0-9 与 `'()+,-./:=?` 和空格)。
127
+ *
128
+ * Builds a PrintableString (only A-Z a-z 0-9 and `'()+,-./:=?` plus space allowed).
129
+ */
130
+ export declare function printableString(value: string): Asn1Node;
131
+ /**
132
+ * 构造 IA5String(仅 ASCII)。
133
+ *
134
+ * Builds an IA5String (ASCII only).
135
+ */
136
+ export declare function ia5String(value: string): Asn1Node;
137
+ /**
138
+ * 构造 UTCTime(1950–2049)。
139
+ *
140
+ * Builds a UTCTime (years 1950–2049).
141
+ */
142
+ export declare function utcTime(date: Date): Asn1Node;
143
+ /**
144
+ * 构造 GeneralizedTime。
145
+ *
146
+ * Builds a GeneralizedTime.
147
+ */
148
+ export declare function generalizedTime(date: Date): Asn1Node;
149
+ /**
150
+ * 按 RFC 5280 自动选择 UTCTime / GeneralizedTime。
151
+ *
152
+ * Picks UTCTime / GeneralizedTime automatically as RFC 5280 requires.
153
+ */
154
+ export declare function time(date: Date): Asn1Node;
155
+ /**
156
+ * INTEGER 最小补码编码。
157
+ *
158
+ * - 0 → `00`;
159
+ * - 正数:最高位为 1 时前置 `00`;
160
+ * - 负数:选择最少字节数 n 使 `-2^(8n-1) <= v`,按 2^(8n) 取模。
161
+ *
162
+ * Minimal two's-complement INTEGER encoding.
163
+ *
164
+ * - 0 → `00`;
165
+ * - positive: prepend `00` when the top bit would otherwise be set;
166
+ * - negative: pick the fewest bytes n such that `-2^(8n-1) <= v`, then reduce modulo
167
+ * 2^(8n).
168
+ */
169
+ export declare function encodeIntegerValue(v: bigint): Uint8Array;
@@ -0,0 +1,414 @@
1
+ /**
2
+ * ASN.1 DER 编码器与构造器。
3
+ *
4
+ * 规则:
5
+ * - `encode()` 按 `cls + constructed + tag` 重建首字节(修复旧实现丢掉
6
+ * constructed 位的问题),对 constructed 节点递归编码子节点;
7
+ * - SET OF 按编码字节排序(DER 要求);
8
+ * - BOOLEAN TRUE 编码为 0xFF;
9
+ * - INTEGER 使用最小补码编码;
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).
22
+ */
23
+ import { encodeOid } from './oid.js';
24
+ import { encodeGeneralizedTime, encodeTime, encodeUtcTime } from './time.js';
25
+ import { Asn1Class, Asn1Error, UniversalTag } from './types.js';
26
+ // ----------------- 基础编码 -----------------
27
+ //
28
+ // ----------------- Basic encoding -----------------
29
+ /**
30
+ * 编码单个节点为 DER 字节。
31
+ *
32
+ * Encodes a single node to DER bytes.
33
+ */
34
+ export function encode(node) {
35
+ const constructed = node.children !== undefined ? true : node.constructed;
36
+ const value = constructed
37
+ ? node.children
38
+ ? concat(node.children.map((child) => encode(child)))
39
+ : node.value
40
+ : node.value;
41
+ const header = concat([encodeTag(node.cls, constructed, node.tag), encodeLength(value.length)]);
42
+ return concat([header, value]);
43
+ }
44
+ /**
45
+ * `encode` 的旧名(兼容 `src/pem/asn1.ts` 的历史导出)。
46
+ *
47
+ * @deprecated 使用 `encode`。
48
+ *
49
+ * Legacy alias of `encode` (kept for the historical exports of `src/pem/asn1.ts`).
50
+ *
51
+ * @deprecated Use `encode`.
52
+ */
53
+ export const encodeDer = encode;
54
+ /**
55
+ * 编码 tag 首字节(含高 tag number 的 base128 展开)。
56
+ *
57
+ * Encodes the tag's leading byte (including base128 expansion of high tag numbers).
58
+ */
59
+ export function encodeTag(cls, constructed, tag) {
60
+ if (!Number.isInteger(tag) || tag < 0) {
61
+ throw new Asn1Error(`encodeTag: invalid tag ${tag}`);
62
+ }
63
+ const base = (cls << 6) | (constructed ? 0x20 : 0);
64
+ if (tag < 0x1f)
65
+ return new Uint8Array([base | tag]);
66
+ const out = [base | 0x1f];
67
+ let v = tag;
68
+ const groups = [];
69
+ do {
70
+ groups.unshift(v % 128);
71
+ v = Math.floor(v / 128);
72
+ } while (v > 0);
73
+ for (let i = 0; i < groups.length - 1; i++)
74
+ groups[i] = groups[i] | 0x80;
75
+ out.push(...groups);
76
+ return new Uint8Array(out);
77
+ }
78
+ /**
79
+ * 编码 definite-length。
80
+ *
81
+ * Encodes a definite length.
82
+ */
83
+ export function encodeLength(length) {
84
+ if (!Number.isInteger(length) || length < 0) {
85
+ throw new Asn1Error(`encodeLength: bad length ${length}`);
86
+ }
87
+ if (length < 0x80)
88
+ return new Uint8Array([length]);
89
+ const bytes = [];
90
+ let v = length;
91
+ while (v > 0) {
92
+ bytes.unshift(v % 256);
93
+ v = Math.floor(v / 256);
94
+ }
95
+ return new Uint8Array([0x80 | bytes.length, ...bytes]);
96
+ }
97
+ // ----------------- 构造器 -----------------
98
+ //
99
+ // ----------------- Builders -----------------
100
+ /**
101
+ * 构造 SEQUENCE。
102
+ *
103
+ * Builds a SEQUENCE.
104
+ */
105
+ export function seq(children) {
106
+ return makeConstructed(Asn1Class.Universal, UniversalTag.Sequence, children);
107
+ }
108
+ /**
109
+ * 构造 SET(保持给定顺序;ASN.1 SET 的排序语义由调用方负责)。
110
+ *
111
+ * Builds a SET, keeping the given order; ordering semantics are the caller's job.
112
+ */
113
+ export function set(children) {
114
+ return makeConstructed(Asn1Class.Universal, UniversalTag.Set, children);
115
+ }
116
+ /**
117
+ * 构造 SET OF(按 DER 编码字节排序)。
118
+ *
119
+ * Builds a SET OF, sorted by encoded DER bytes.
120
+ */
121
+ export function setOf(children) {
122
+ const sorted = children
123
+ .map((node) => ({ node, bytes: encode(node) }))
124
+ .sort((a, b) => compareBytes(a.bytes, b.bytes))
125
+ .map((entry) => entry.node);
126
+ return makeConstructed(Asn1Class.Universal, UniversalTag.Set, sorted);
127
+ }
128
+ /**
129
+ * 构造 `[tag] EXPLICIT` 包装。
130
+ *
131
+ * Builds a `[tag] EXPLICIT` wrapper.
132
+ */
133
+ export function explicit(tag, inner) {
134
+ const value = encode(inner);
135
+ return {
136
+ cls: Asn1Class.ContextSpecific,
137
+ tag,
138
+ constructed: true,
139
+ indefinite: false,
140
+ length: value.length,
141
+ value,
142
+ children: [inner],
143
+ raw: concat([
144
+ encodeTag(Asn1Class.ContextSpecific, true, tag),
145
+ encodeLength(value.length),
146
+ value,
147
+ ]),
148
+ };
149
+ }
150
+ /**
151
+ * 构造 `[tag] IMPLICIT` 包装:只替换外层标签,内容保持不变。
152
+ *
153
+ * Builds a `[tag] IMPLICIT` wrapper: only the outer tag is replaced, the content is
154
+ * kept unchanged.
155
+ */
156
+ export function implicit(tag, inner, cls = Asn1Class.ContextSpecific) {
157
+ const constructed = inner.children !== undefined ? true : inner.constructed;
158
+ const value = inner.children ? concat(inner.children.map((child) => encode(child))) : inner.value;
159
+ return {
160
+ cls,
161
+ tag,
162
+ constructed,
163
+ indefinite: false,
164
+ length: value.length,
165
+ value,
166
+ children: inner.children,
167
+ raw: concat([encodeTag(cls, constructed, tag), encodeLength(value.length), value]),
168
+ };
169
+ }
170
+ /**
171
+ * 构造 BIT STRING。`unusedBits` 为末尾未使用位数(0..7)。
172
+ *
173
+ * Builds a BIT STRING; `unusedBits` is the number of unused trailing bits (0..7).
174
+ */
175
+ export function bitString(bytes, unusedBits = 0) {
176
+ if (!Number.isInteger(unusedBits) || unusedBits < 0 || unusedBits > 7) {
177
+ throw new RangeError(`bitString: unusedBits must be 0..7, got ${unusedBits}`);
178
+ }
179
+ const value = new Uint8Array(bytes.length + 1);
180
+ value[0] = unusedBits;
181
+ value.set(bytes, 1);
182
+ return makePrimitive(UniversalTag.BitString, value);
183
+ }
184
+ /**
185
+ * 构造 OCTET STRING。
186
+ *
187
+ * Builds an OCTET STRING.
188
+ */
189
+ export function octetString(bytes) {
190
+ return makePrimitive(UniversalTag.OctetString, bytes);
191
+ }
192
+ /**
193
+ * 构造 BOOLEAN。
194
+ *
195
+ * Builds a BOOLEAN.
196
+ */
197
+ export function boolean(value) {
198
+ return makePrimitive(UniversalTag.Boolean, new Uint8Array([value ? 0xff : 0x00]));
199
+ }
200
+ /**
201
+ * 构造 NULL。
202
+ *
203
+ * Builds a NULL.
204
+ */
205
+ export function nullValue() {
206
+ return makePrimitive(UniversalTag.Null, new Uint8Array(0));
207
+ }
208
+ /**
209
+ * 构造 INTEGER(最小补码编码)。
210
+ *
211
+ * Builds an INTEGER (minimal two's-complement encoding).
212
+ */
213
+ export function integer(value) {
214
+ const v = typeof value === 'number' ? BigInt(value) : value;
215
+ if (typeof v !== 'bigint')
216
+ throw new Asn1Error('integer: value must be bigint or number');
217
+ return makePrimitive(UniversalTag.Integer, encodeIntegerValue(v));
218
+ }
219
+ /**
220
+ * 构造 OBJECT IDENTIFIER。
221
+ *
222
+ * Builds an OBJECT IDENTIFIER.
223
+ */
224
+ export function oid(value) {
225
+ return makePrimitive(UniversalTag.ObjectIdentifier, encodeOid(value));
226
+ }
227
+ /**
228
+ * 构造 UTF8String。
229
+ *
230
+ * Builds a UTF8String.
231
+ */
232
+ export function utf8String(value) {
233
+ return makePrimitive(UniversalTag.Utf8String, new TextEncoder().encode(value));
234
+ }
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
+ */
240
+ export function printableString(value) {
241
+ if (!/^[A-Za-z0-9 '()+,\-./:=?]*$/.test(value)) {
242
+ throw new Asn1Error(`printableString: unsupported character in "${value}"`);
243
+ }
244
+ return makePrimitive(UniversalTag.PrintableString, asciiBytes(value));
245
+ }
246
+ /**
247
+ * 构造 IA5String(仅 ASCII)。
248
+ *
249
+ * Builds an IA5String (ASCII only).
250
+ */
251
+ export function ia5String(value) {
252
+ for (let i = 0; i < value.length; i++) {
253
+ if (value.charCodeAt(i) > 0x7f) {
254
+ throw new Asn1Error('ia5String: non-ASCII character');
255
+ }
256
+ }
257
+ return makePrimitive(UniversalTag.Ia5String, asciiBytes(value));
258
+ }
259
+ /**
260
+ * 构造 UTCTime(1950–2049)。
261
+ *
262
+ * Builds a UTCTime (years 1950–2049).
263
+ */
264
+ export function utcTime(date) {
265
+ return makePrimitive(UniversalTag.UtcTime, asciiBytes(encodeUtcTime(date)));
266
+ }
267
+ /**
268
+ * 构造 GeneralizedTime。
269
+ *
270
+ * Builds a GeneralizedTime.
271
+ */
272
+ export function generalizedTime(date) {
273
+ return makePrimitive(UniversalTag.GeneralizedTime, asciiBytes(encodeGeneralizedTime(date)));
274
+ }
275
+ /**
276
+ * 按 RFC 5280 自动选择 UTCTime / GeneralizedTime。
277
+ *
278
+ * Picks UTCTime / GeneralizedTime automatically as RFC 5280 requires.
279
+ */
280
+ export function time(date) {
281
+ return makePrimitive(isUtcYear(date) ? UniversalTag.UtcTime : UniversalTag.GeneralizedTime, asciiBytes(encodeTime(date)));
282
+ }
283
+ // ----------------- 内部 -----------------
284
+ //
285
+ // ----------------- Internals -----------------
286
+ /**
287
+ * 构造 UNIVERSAL primitive 节点。
288
+ *
289
+ * Builds a UNIVERSAL primitive node.
290
+ */
291
+ function makePrimitive(tag, value) {
292
+ return {
293
+ cls: Asn1Class.Universal,
294
+ tag,
295
+ constructed: false,
296
+ indefinite: false,
297
+ length: value.length,
298
+ value,
299
+ raw: concat([encodeTag(Asn1Class.Universal, false, tag), encodeLength(value.length), value]),
300
+ };
301
+ }
302
+ /**
303
+ * 构造 UNIVERSAL constructed 节点(value 由子节点编码拼接而成)。
304
+ *
305
+ * Builds a UNIVERSAL constructed node whose value is the concatenated encoded
306
+ * children.
307
+ */
308
+ function makeConstructed(cls, tag, children) {
309
+ const value = concat(children.map((child) => encode(child)));
310
+ return {
311
+ cls,
312
+ tag,
313
+ constructed: true,
314
+ indefinite: false,
315
+ length: value.length,
316
+ value,
317
+ children,
318
+ raw: concat([encodeTag(cls, true, tag), encodeLength(value.length), value]),
319
+ };
320
+ }
321
+ /**
322
+ * 判断日期年份是否落在 UTCTime 适用范围(1950–2049)。
323
+ *
324
+ * Whether the year falls in the UTCTime range (1950–2049).
325
+ */
326
+ function isUtcYear(date) {
327
+ if (!(date instanceof Date) || Number.isNaN(date.getTime()))
328
+ return false;
329
+ const year = date.getUTCFullYear();
330
+ return year >= 1950 && year <= 2049;
331
+ }
332
+ /**
333
+ * INTEGER 最小补码编码。
334
+ *
335
+ * - 0 → `00`;
336
+ * - 正数:最高位为 1 时前置 `00`;
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).
345
+ */
346
+ export function encodeIntegerValue(v) {
347
+ if (v === 0n)
348
+ return new Uint8Array([0]);
349
+ if (v > 0n) {
350
+ let n = 1;
351
+ while (v >= 1n << BigInt(8 * n - 1))
352
+ n++;
353
+ const out = new Uint8Array(n);
354
+ let x = v;
355
+ for (let i = n - 1; i >= 0; i--) {
356
+ out[i] = Number(x & 0xffn);
357
+ x >>= 8n;
358
+ }
359
+ return out;
360
+ }
361
+ let n = 1;
362
+ while (v < -(1n << BigInt(8 * n - 1)))
363
+ n++;
364
+ let x = (1n << BigInt(8 * n)) + v;
365
+ const out = new Uint8Array(n);
366
+ for (let i = n - 1; i >= 0; i--) {
367
+ out[i] = Number(x & 0xffn);
368
+ x >>= 8n;
369
+ }
370
+ return out;
371
+ }
372
+ /**
373
+ * 字符串 → ASCII 字节(高于 0x7f 的码位被截断,调用方负责预先校验)。
374
+ *
375
+ * String to ASCII bytes; code points above 0x7f are truncated, so callers must
376
+ * validate beforehand.
377
+ */
378
+ function asciiBytes(text) {
379
+ const out = new Uint8Array(text.length);
380
+ for (let i = 0; i < text.length; i++)
381
+ out[i] = text.charCodeAt(i) & 0x7f;
382
+ return out;
383
+ }
384
+ /**
385
+ * 字节字典序比较(DER SET OF 排序依据)。
386
+ *
387
+ * Lexicographic byte comparison, the ordering rule for DER SET OF.
388
+ */
389
+ function compareBytes(a, b) {
390
+ const n = Math.min(a.length, b.length);
391
+ for (let i = 0; i < n; i++) {
392
+ const d = a[i] - b[i];
393
+ if (d !== 0)
394
+ return d;
395
+ }
396
+ return a.length - b.length;
397
+ }
398
+ /**
399
+ * 拼多个字节数组为一个新数组。
400
+ *
401
+ * Concatenates byte arrays into a new array.
402
+ */
403
+ function concat(parts) {
404
+ let total = 0;
405
+ for (const p of parts)
406
+ total += p.length;
407
+ const out = new Uint8Array(total);
408
+ let offset = 0;
409
+ for (const p of parts) {
410
+ out.set(p, offset);
411
+ offset += p.length;
412
+ }
413
+ return out;
414
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ASN.1 内部层 barrel。
3
+ *
4
+ * **不进入主入口导出**(spec Anti-Goal:不公开底层 DER/大数接口)。
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.
12
+ */
13
+ export * from './decode.js';
14
+ export * from './encode.js';
15
+ export * from './oid.js';
16
+ export * from './time.js';
17
+ export * from './types.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ASN.1 内部层 barrel。
3
+ *
4
+ * **不进入主入口导出**(spec Anti-Goal:不公开底层 DER/大数接口)。
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.
12
+ */
13
+ export * from './decode.js';
14
+ export * from './encode.js';
15
+ export * from './oid.js';
16
+ export * from './time.js';
17
+ export * from './types.js';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * OBJECT IDENTIFIER 编解码。
3
+ *
4
+ * 与旧实现的差异:
5
+ * - 用 `bigint` 累加,不再受 32 位按位运算限制(`1.2.840.113549...` 这类
6
+ * 长组件不会溢出);
7
+ * - 首个子标识符也走 base128 编码,支持 `2.999` 这类第二组件 ≥ 40 的 OID;
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.
18
+ */
19
+ /**
20
+ * 点分 OID → 内容字节(不含 tag 与 length)。
21
+ *
22
+ * @param oid 形如 `"1.2.156.10197.1.100"`。
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.
29
+ */
30
+ export declare function encodeOid(oid: string): Uint8Array;
31
+ /**
32
+ * 内容字节 → 点分 OID。
33
+ *
34
+ * @throws Asn1Error 空输入、截断或非法 base128 编码。
35
+ *
36
+ * Content bytes → dotted OID.
37
+ *
38
+ * @throws Asn1Error On empty input, truncation, or an invalid base128 encoding.
39
+ */
40
+ export declare function decodeOid(bytes: Uint8Array): string;