@freedomofpress/sigstore-browser 0.1.0 → 0.1.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/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/interfaces.d.ts +1 -15
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js +2 -18
- package/dist/interfaces.js.map +1 -1
- package/dist/rfc3161/timestamp.d.ts +1 -1
- package/dist/rfc3161/timestamp.d.ts.map +1 -1
- package/dist/rfc3161/timestamp.js +3 -5
- package/dist/rfc3161/timestamp.js.map +1 -1
- package/dist/rfc3161/tstinfo.d.ts +1 -1
- package/dist/rfc3161/tstinfo.d.ts.map +1 -1
- package/dist/rfc3161/tstinfo.js +18 -4
- package/dist/rfc3161/tstinfo.js.map +1 -1
- package/dist/sigstore.d.ts +1 -1
- package/dist/sigstore.d.ts.map +1 -1
- package/dist/sigstore.js +6 -8
- package/dist/sigstore.js.map +1 -1
- package/dist/timestamp/tsa.d.ts +1 -1
- package/dist/timestamp/tsa.d.ts.map +1 -1
- package/dist/timestamp/tsa.js +4 -5
- package/dist/timestamp/tsa.js.map +1 -1
- package/dist/tlog/body.js +1 -1
- package/dist/tlog/body.js.map +1 -1
- package/dist/tlog/checkpoint.d.ts.map +1 -1
- package/dist/tlog/checkpoint.js +6 -7
- package/dist/tlog/checkpoint.js.map +1 -1
- package/dist/tlog/dsse.js +3 -3
- package/dist/tlog/dsse.js.map +1 -1
- package/dist/tlog/hashedrekord.js +1 -1
- package/dist/tlog/hashedrekord.js.map +1 -1
- package/dist/tlog/intoto.js +2 -2
- package/dist/tlog/intoto.js.map +1 -1
- package/dist/tlog/merkle.js +4 -4
- package/dist/tlog/merkle.js.map +1 -1
- package/dist/trust/tuf.d.ts +1 -1
- package/dist/trust/tuf.d.ts.map +1 -1
- package/dist/trust/tuf.js +4 -4
- package/dist/trust/tuf.js.map +1 -1
- package/dist/x509/cert.d.ts +1 -1
- package/dist/x509/cert.d.ts.map +1 -1
- package/dist/x509/cert.js +4 -7
- package/dist/x509/cert.js.map +1 -1
- package/dist/x509/chain.d.ts.map +1 -1
- package/dist/x509/chain.js +16 -5
- package/dist/x509/chain.js.map +1 -1
- package/dist/x509/ext.d.ts +1 -1
- package/dist/x509/ext.d.ts.map +1 -1
- package/dist/x509/ext.js +17 -3
- package/dist/x509/ext.js.map +1 -1
- package/dist/x509/sct.d.ts.map +1 -1
- package/dist/x509/sct.js +2 -4
- package/dist/x509/sct.js.map +1 -1
- package/package.json +4 -3
- package/src/cli.ts +6 -1
- package/src/interfaces.ts +2 -17
- package/src/rfc3161/timestamp.ts +3 -5
- package/src/rfc3161/tstinfo.ts +3 -5
- package/src/sigstore.ts +17 -16
- package/src/timestamp/tsa.ts +5 -6
- package/src/tlog/body.ts +1 -1
- package/src/tlog/checkpoint.ts +13 -7
- package/src/tlog/dsse.ts +3 -3
- package/src/tlog/hashedrekord.ts +1 -1
- package/src/tlog/intoto.ts +2 -2
- package/src/tlog/merkle.ts +4 -4
- package/src/trust/tuf.ts +6 -6
- package/src/x509/cert.ts +11 -7
- package/src/x509/chain.ts +6 -6
- package/src/x509/ext.ts +2 -4
- package/src/x509/sct.ts +2 -4
- package/dist/asn1/error.d.ts +0 -5
- package/dist/asn1/error.d.ts.map +0 -1
- package/dist/asn1/error.js +0 -20
- package/dist/asn1/error.js.map +0 -1
- package/dist/asn1/index.d.ts +0 -2
- package/dist/asn1/index.d.ts.map +0 -1
- package/dist/asn1/index.js +0 -17
- package/dist/asn1/index.js.map +0 -1
- package/dist/asn1/length.d.ts +0 -4
- package/dist/asn1/length.d.ts.map +0 -1
- package/dist/asn1/length.js +0 -59
- package/dist/asn1/length.js.map +0 -1
- package/dist/asn1/obj.d.ts +0 -15
- package/dist/asn1/obj.d.ts.map +0 -1
- package/dist/asn1/obj.js +0 -153
- package/dist/asn1/obj.js.map +0 -1
- package/dist/asn1/parse.d.ts +0 -7
- package/dist/asn1/parse.d.ts.map +0 -1
- package/dist/asn1/parse.js +0 -118
- package/dist/asn1/parse.js.map +0 -1
- package/dist/asn1/tag.d.ts +0 -17
- package/dist/asn1/tag.d.ts.map +0 -1
- package/dist/asn1/tag.js +0 -86
- package/dist/asn1/tag.js.map +0 -1
- package/dist/canonicalize.d.ts +0 -2
- package/dist/canonicalize.d.ts.map +0 -1
- package/dist/canonicalize.js +0 -64
- package/dist/canonicalize.js.map +0 -1
- package/dist/crypto.d.ts +0 -5
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js +0 -260
- package/dist/crypto.js.map +0 -1
- package/dist/encoding.d.ts +0 -17
- package/dist/encoding.d.ts.map +0 -1
- package/dist/encoding.js +0 -112
- package/dist/encoding.js.map +0 -1
- package/dist/pem.d.ts +0 -3
- package/dist/pem.d.ts.map +0 -1
- package/dist/pem.js +0 -41
- package/dist/pem.js.map +0 -1
- package/dist/stream.d.ts +0 -22
- package/dist/stream.d.ts.map +0 -1
- package/dist/stream.js +0 -114
- package/dist/stream.js.map +0 -1
- package/src/asn1/error.ts +0 -18
- package/src/asn1/index.ts +0 -16
- package/src/asn1/length.ts +0 -71
- package/src/asn1/obj.ts +0 -184
- package/src/asn1/parse.ts +0 -146
- package/src/asn1/tag.ts +0 -105
- package/src/canonicalize.ts +0 -61
- package/src/crypto.ts +0 -310
- package/src/encoding.ts +0 -141
- package/src/pem.ts +0 -48
- package/src/stream.ts +0 -141
- package/src/types/tuf-browser.d.ts +0 -13
package/src/asn1/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2023 The Sigstore Authors.
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
export { ASN1Obj } from "./obj.js";
|
package/src/asn1/length.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2023 The Sigstore Authors.
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { ByteStream } from "../stream.js";
|
|
18
|
-
import { ASN1ParseError } from "./error.js";
|
|
19
|
-
|
|
20
|
-
// Decodes the length of a DER-encoded ANS.1 element from the supplied stream.
|
|
21
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-encoded-length-and-value-bytes
|
|
22
|
-
export function decodeLength(stream: ByteStream): number {
|
|
23
|
-
const buf = stream.getUint8();
|
|
24
|
-
|
|
25
|
-
// If the most significant bit is UNSET the length is just the value of the
|
|
26
|
-
// byte.
|
|
27
|
-
if ((buf & 0x80) === 0x00) {
|
|
28
|
-
return buf;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Otherwise, the lower 7 bits of the first byte indicate the number of bytes
|
|
32
|
-
// that follow to encode the length.
|
|
33
|
-
const byteCount = buf & 0x7f;
|
|
34
|
-
|
|
35
|
-
// Ensure the encoded length can safely fit in a JS number.
|
|
36
|
-
if (byteCount > 6) {
|
|
37
|
-
throw new ASN1ParseError("length exceeds 6 byte limit");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Iterate over the bytes that encode the length.
|
|
41
|
-
let len = 0;
|
|
42
|
-
for (let i = 0; i < byteCount; i++) {
|
|
43
|
-
len = len * 256 + stream.getUint8();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// This is a valid ASN.1 length encoding, but we don't support it.
|
|
47
|
-
if (len === 0) {
|
|
48
|
-
throw new ASN1ParseError("indefinite length encoding not supported");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return len;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Translates the supplied value to a DER-encoded length.
|
|
55
|
-
export function encodeLength(len: number): Uint8Array {
|
|
56
|
-
if (len < 128) {
|
|
57
|
-
return new Uint8Array([len]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Bitwise operations on large numbers are not supported in JS, so we need to
|
|
61
|
-
// use BigInts.
|
|
62
|
-
let val = BigInt(len);
|
|
63
|
-
const bytes = [];
|
|
64
|
-
|
|
65
|
-
while (val > 0n) {
|
|
66
|
-
bytes.unshift(Number(val & 255n));
|
|
67
|
-
val = val >> 8n;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return new Uint8Array([0x80 | bytes.length, ...bytes]);
|
|
71
|
-
}
|
package/src/asn1/obj.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2023 The Sigstore Authors.
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { toArrayBuffer } from "../encoding.js";
|
|
17
|
-
import { ByteStream } from "../stream.js";
|
|
18
|
-
import { ASN1ParseError, ASN1TypeError } from "./error.js";
|
|
19
|
-
import { decodeLength, encodeLength } from "./length.js";
|
|
20
|
-
import {
|
|
21
|
-
parseBitString,
|
|
22
|
-
parseBoolean,
|
|
23
|
-
parseInteger,
|
|
24
|
-
parseOID,
|
|
25
|
-
parseTime,
|
|
26
|
-
} from "./parse.js";
|
|
27
|
-
import { ASN1Tag } from "./tag.js";
|
|
28
|
-
|
|
29
|
-
export class ASN1Obj {
|
|
30
|
-
readonly tag: ASN1Tag;
|
|
31
|
-
readonly subs: ASN1Obj[];
|
|
32
|
-
readonly value: Uint8Array;
|
|
33
|
-
|
|
34
|
-
constructor(tag: ASN1Tag, value: Uint8Array, subs: ASN1Obj[]) {
|
|
35
|
-
this.tag = tag;
|
|
36
|
-
this.value = value;
|
|
37
|
-
this.subs = subs;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Constructs an ASN.1 object from a Buffer of DER-encoded bytes.
|
|
41
|
-
public static parseBuffer(buf: Uint8Array): ASN1Obj {
|
|
42
|
-
return parseStream(new ByteStream(toArrayBuffer(buf)));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public toDER(): Uint8Array {
|
|
46
|
-
const valueStream = new ByteStream();
|
|
47
|
-
|
|
48
|
-
if (this.subs.length > 0) {
|
|
49
|
-
for (const sub of this.subs) {
|
|
50
|
-
valueStream.appendView(sub.toDER());
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
valueStream.appendView(this.value);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const value = valueStream.buffer;
|
|
57
|
-
|
|
58
|
-
// Concat tag/length/value
|
|
59
|
-
const obj = new ByteStream();
|
|
60
|
-
obj.appendChar(this.tag.toDER());
|
|
61
|
-
obj.appendView(encodeLength(value.length));
|
|
62
|
-
obj.appendView(value);
|
|
63
|
-
|
|
64
|
-
return obj.buffer;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/////////////////////////////////////////////////////////////////////////////
|
|
68
|
-
// Convenience methods for parsing ASN.1 primitives into JS types
|
|
69
|
-
|
|
70
|
-
// Returns the ASN.1 object's value as a boolean. Throws an error if the
|
|
71
|
-
// object is not a boolean.
|
|
72
|
-
public toBoolean(): boolean {
|
|
73
|
-
if (!this.tag.isBoolean()) {
|
|
74
|
-
throw new ASN1TypeError("not a boolean");
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return parseBoolean(this.value);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Returns the ASN.1 object's value as a BigInt. Throws an error if the
|
|
81
|
-
// object is not an integer.
|
|
82
|
-
public toInteger(): bigint {
|
|
83
|
-
if (!this.tag.isInteger()) {
|
|
84
|
-
throw new ASN1TypeError("not an integer");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return parseInteger(this.value);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Returns the ASN.1 object's value as an OID string. Throws an error if the
|
|
91
|
-
// object is not an OID.
|
|
92
|
-
public toOID(): string {
|
|
93
|
-
if (!this.tag.isOID()) {
|
|
94
|
-
throw new ASN1TypeError("not an OID");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return parseOID(this.value);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Returns the ASN.1 object's value as a Date. Throws an error if the object
|
|
101
|
-
// is not either a UTCTime or a GeneralizedTime.
|
|
102
|
-
public toDate(): Date {
|
|
103
|
-
switch (true) {
|
|
104
|
-
case this.tag.isUTCTime():
|
|
105
|
-
return parseTime(this.value, true);
|
|
106
|
-
case this.tag.isGeneralizedTime():
|
|
107
|
-
return parseTime(this.value, false);
|
|
108
|
-
default:
|
|
109
|
-
throw new ASN1TypeError("not a date");
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Returns the ASN.1 object's value as a number[] where each number is the
|
|
114
|
-
// value of a bit in the bit string. Throws an error if the object is not a
|
|
115
|
-
// bit string.
|
|
116
|
-
public toBitString(): number[] {
|
|
117
|
-
if (!this.tag.isBitString()) {
|
|
118
|
-
throw new ASN1TypeError("not a bit string");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return parseBitString(this.value);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/////////////////////////////////////////////////////////////////////////////
|
|
126
|
-
// Internal stream parsing functions
|
|
127
|
-
|
|
128
|
-
function parseStream(stream: ByteStream): ASN1Obj {
|
|
129
|
-
// Parse tag, length, and value from stream
|
|
130
|
-
const tag = new ASN1Tag(stream.getUint8());
|
|
131
|
-
const len = decodeLength(stream);
|
|
132
|
-
const value = stream.slice(stream.position, len);
|
|
133
|
-
|
|
134
|
-
const start = stream.position;
|
|
135
|
-
|
|
136
|
-
let subs: ASN1Obj[] = [];
|
|
137
|
-
// If the object is constructed, parse its children. Sometimes, children
|
|
138
|
-
// are embedded in OCTESTRING objects, so we need to check those
|
|
139
|
-
// for children as well.
|
|
140
|
-
if (tag.constructed) {
|
|
141
|
-
subs = collectSubs(stream, len);
|
|
142
|
-
} else if (tag.isOctetString()) {
|
|
143
|
-
// Attempt to parse children of OCTETSTRING objects. If anything fails,
|
|
144
|
-
// assume the object is not constructed and treat as primitive.
|
|
145
|
-
try {
|
|
146
|
-
subs = collectSubs(stream, len);
|
|
147
|
-
} catch {
|
|
148
|
-
// Fail silently and treat as primitive
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// If there are no children, move stream cursor to the end of the object
|
|
153
|
-
if (subs.length === 0) {
|
|
154
|
-
stream.seek(start + len);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return new ASN1Obj(tag, value, subs);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function collectSubs(stream: ByteStream, len: number): ASN1Obj[] {
|
|
161
|
-
// Calculate end of object content
|
|
162
|
-
const end = stream.position + len;
|
|
163
|
-
|
|
164
|
-
// Make sure there are enough bytes left in the stream. This should never
|
|
165
|
-
// happen, cause it'll get caught when the stream is sliced in parseStream.
|
|
166
|
-
// Leaving as an extra check just in case.
|
|
167
|
-
/* istanbul ignore if */
|
|
168
|
-
if (end > stream.length) {
|
|
169
|
-
throw new ASN1ParseError("invalid length");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Parse all children
|
|
173
|
-
const subs: ASN1Obj[] = [];
|
|
174
|
-
while (stream.position < end) {
|
|
175
|
-
subs.push(parseStream(stream));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// When we're done parsing children, we should be at the end of the object
|
|
179
|
-
if (stream.position !== end) {
|
|
180
|
-
throw new ASN1ParseError("invalid length");
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return subs;
|
|
184
|
-
}
|
package/src/asn1/parse.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2023 The Sigstore Authors.
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { Uint8ArrayToString } from "../encoding.js";
|
|
18
|
-
|
|
19
|
-
const RE_TIME_SHORT_YEAR =
|
|
20
|
-
/^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d{3})?Z$/;
|
|
21
|
-
const RE_TIME_LONG_YEAR =
|
|
22
|
-
/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d{3})?Z$/;
|
|
23
|
-
|
|
24
|
-
// Parse a BigInt from the DER-encoded buffer
|
|
25
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-integer
|
|
26
|
-
export function parseInteger(buf: Uint8Array): bigint {
|
|
27
|
-
let pos = 0;
|
|
28
|
-
const end = buf.length;
|
|
29
|
-
let val = buf[pos];
|
|
30
|
-
const neg = val > 0x7f;
|
|
31
|
-
|
|
32
|
-
// Consume any padding bytes
|
|
33
|
-
const pad = neg ? 0xff : 0x00;
|
|
34
|
-
while (val == pad && ++pos < end) {
|
|
35
|
-
val = buf[pos];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Calculate remaining bytes to read
|
|
39
|
-
const len = end - pos;
|
|
40
|
-
|
|
41
|
-
if (len === 0) return BigInt(neg ? -1 : 0);
|
|
42
|
-
|
|
43
|
-
// Handle two's complement for negative numbers
|
|
44
|
-
val = neg ? val - 256 : val;
|
|
45
|
-
|
|
46
|
-
// Parse remaining bytes
|
|
47
|
-
let n = BigInt(val);
|
|
48
|
-
for (let i = pos + 1; i < end; ++i) {
|
|
49
|
-
n = n * BigInt(256) + BigInt(buf[i]);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return n;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Parse an ASCII string from the DER-encoded buffer
|
|
56
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-basic-types#boolean
|
|
57
|
-
export function parseStringASCII(buf: Uint8Array): string {
|
|
58
|
-
return Uint8ArrayToString(buf);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Parse a Date from the DER-encoded buffer
|
|
62
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5.1
|
|
63
|
-
export function parseTime(buf: Uint8Array, shortYear: boolean): Date {
|
|
64
|
-
const timeStr = parseStringASCII(buf);
|
|
65
|
-
|
|
66
|
-
// Parse the time string into matches - captured groups start at index 1
|
|
67
|
-
const m = shortYear
|
|
68
|
-
? RE_TIME_SHORT_YEAR.exec(timeStr)
|
|
69
|
-
: RE_TIME_LONG_YEAR.exec(timeStr);
|
|
70
|
-
|
|
71
|
-
if (!m) {
|
|
72
|
-
throw new Error("invalid time");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Translate dates with a 2-digit year to 4 digits per the spec
|
|
76
|
-
if (shortYear) {
|
|
77
|
-
let year = Number(m[1]);
|
|
78
|
-
year += year >= 50 ? 1900 : 2000;
|
|
79
|
-
m[1] = year.toString();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Translate to ISO8601 format and parse
|
|
83
|
-
return new Date(`${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Parse an OID from the DER-encoded buffer
|
|
87
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier
|
|
88
|
-
export function parseOID(buf: Uint8Array): string {
|
|
89
|
-
let pos = 0;
|
|
90
|
-
const end = buf.length;
|
|
91
|
-
|
|
92
|
-
// Consume first byte which encodes the first two OID components
|
|
93
|
-
let n = buf[pos++];
|
|
94
|
-
const first = Math.floor(n / 40);
|
|
95
|
-
const second = n % 40;
|
|
96
|
-
|
|
97
|
-
let oid = `${first}.${second}`;
|
|
98
|
-
|
|
99
|
-
// Consume remaining bytes
|
|
100
|
-
let val = 0;
|
|
101
|
-
for (; pos < end; ++pos) {
|
|
102
|
-
n = buf[pos];
|
|
103
|
-
val = (val << 7) + (n & 0x7f);
|
|
104
|
-
|
|
105
|
-
// If the left-most bit is NOT set, then this is the last byte in the
|
|
106
|
-
// sequence and we can add the value to the OID and reset the accumulator
|
|
107
|
-
if ((n & 0x80) === 0) {
|
|
108
|
-
oid += `.${val}`;
|
|
109
|
-
val = 0;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return oid;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Parse a boolean from the DER-encoded buffer
|
|
117
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-basic-types#boolean
|
|
118
|
-
export function parseBoolean(buf: Uint8Array): boolean {
|
|
119
|
-
return buf[0] !== 0;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Parse a bit string from the DER-encoded buffer
|
|
123
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bit-string
|
|
124
|
-
export function parseBitString(buf: Uint8Array): number[] {
|
|
125
|
-
// First byte tell us how many unused bits are in the last byte
|
|
126
|
-
const unused = buf[0];
|
|
127
|
-
|
|
128
|
-
const start = 1;
|
|
129
|
-
const end = buf.length;
|
|
130
|
-
const bits = [];
|
|
131
|
-
|
|
132
|
-
for (let i = start; i < end; ++i) {
|
|
133
|
-
const byte = buf[i];
|
|
134
|
-
|
|
135
|
-
// The skip value is only used for the last byte
|
|
136
|
-
const skip = i === end - 1 ? unused : 0;
|
|
137
|
-
|
|
138
|
-
// Iterate over each bit in the byte (most significant first)
|
|
139
|
-
for (let j = 7; j >= skip; --j) {
|
|
140
|
-
// Read the bit and add it to the bit string
|
|
141
|
-
bits.push((byte >> j) & 0x01);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return bits;
|
|
146
|
-
}
|
package/src/asn1/tag.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2023 The Sigstore Authors.
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { ASN1ParseError } from "./error.js";
|
|
17
|
-
|
|
18
|
-
const UNIVERSAL_TAG = {
|
|
19
|
-
BOOLEAN: 0x01,
|
|
20
|
-
INTEGER: 0x02,
|
|
21
|
-
BIT_STRING: 0x03,
|
|
22
|
-
OCTET_STRING: 0x04,
|
|
23
|
-
OBJECT_IDENTIFIER: 0x06,
|
|
24
|
-
SEQUENCE: 0x10,
|
|
25
|
-
SET: 0x11,
|
|
26
|
-
PRINTABLE_STRING: 0x13,
|
|
27
|
-
UTC_TIME: 0x17,
|
|
28
|
-
GENERALIZED_TIME: 0x18,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const TAG_CLASS = {
|
|
32
|
-
UNIVERSAL: 0x00,
|
|
33
|
-
APPLICATION: 0x01,
|
|
34
|
-
CONTEXT_SPECIFIC: 0x02,
|
|
35
|
-
PRIVATE: 0x03,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-encoded-tag-bytes
|
|
39
|
-
export class ASN1Tag {
|
|
40
|
-
readonly number: number;
|
|
41
|
-
readonly constructed: boolean;
|
|
42
|
-
readonly class: number;
|
|
43
|
-
|
|
44
|
-
constructor(enc: number) {
|
|
45
|
-
// Bits 0 through 4 are the tag number
|
|
46
|
-
this.number = enc & 0x1f;
|
|
47
|
-
|
|
48
|
-
// Bit 5 is the constructed bit
|
|
49
|
-
this.constructed = (enc & 0x20) === 0x20;
|
|
50
|
-
|
|
51
|
-
// Bit 6 & 7 are the class
|
|
52
|
-
this.class = enc >> 6;
|
|
53
|
-
|
|
54
|
-
if (this.number === 0x1f) {
|
|
55
|
-
throw new ASN1ParseError("long form tags not supported");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (this.class === TAG_CLASS.UNIVERSAL && this.number === 0x00) {
|
|
59
|
-
throw new ASN1ParseError("unsupported tag 0x00");
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public isUniversal(): boolean {
|
|
64
|
-
return this.class === TAG_CLASS.UNIVERSAL;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public isContextSpecific(num?: number): boolean {
|
|
68
|
-
const res = this.class === TAG_CLASS.CONTEXT_SPECIFIC;
|
|
69
|
-
return num !== undefined ? res && this.number === num : res;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public isBoolean(): boolean {
|
|
73
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.BOOLEAN;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
public isInteger(): boolean {
|
|
77
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.INTEGER;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public isBitString(): boolean {
|
|
81
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.BIT_STRING;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public isOctetString(): boolean {
|
|
85
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.OCTET_STRING;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public isOID(): boolean {
|
|
89
|
-
return (
|
|
90
|
-
this.isUniversal() && this.number === UNIVERSAL_TAG.OBJECT_IDENTIFIER
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
public isUTCTime(): boolean {
|
|
95
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.UTC_TIME;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
public isGeneralizedTime(): boolean {
|
|
99
|
-
return this.isUniversal() && this.number === UNIVERSAL_TAG.GENERALIZED_TIME;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
public toDER(): number {
|
|
103
|
-
return this.number | (this.constructed ? 0x20 : 0x00) | (this.class << 6);
|
|
104
|
-
}
|
|
105
|
-
}
|
package/src/canonicalize.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// From https://github.com/theupdateframework/tuf-js/blob/38d537ea883e8bb38ee6ab17b5f59ee479d0eab2/packages/canonical-json/lib/index.js
|
|
2
|
-
|
|
3
|
-
const COMMA = ",";
|
|
4
|
-
const COLON = ":";
|
|
5
|
-
const LEFT_SQUARE_BRACKET = "[";
|
|
6
|
-
const RIGHT_SQUARE_BRACKET = "]";
|
|
7
|
-
const LEFT_CURLY_BRACKET = "{";
|
|
8
|
-
const RIGHT_CURLY_BRACKET = "}";
|
|
9
|
-
|
|
10
|
-
function canonicalizeString(string: string): string {
|
|
11
|
-
const escapedString = string.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
12
|
-
return '"' + escapedString + '"';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Recursively encodes the supplied object according to the canonical JSON form
|
|
16
|
-
// as specified at http://wiki.laptop.org/go/Canonical_JSON. It's a restricted
|
|
17
|
-
// dialect of JSON in which keys are lexically sorted, floats are not allowed,
|
|
18
|
-
// and only double quotes and backslashes are escaped.
|
|
19
|
-
export function canonicalize(object: object): string {
|
|
20
|
-
const buffer: string[] = [];
|
|
21
|
-
if (typeof object === "string") {
|
|
22
|
-
buffer.push(canonicalizeString(object));
|
|
23
|
-
} else if (typeof object === "boolean") {
|
|
24
|
-
buffer.push(JSON.stringify(object));
|
|
25
|
-
} else if (Number.isInteger(object)) {
|
|
26
|
-
buffer.push(JSON.stringify(object));
|
|
27
|
-
} else if (object === null) {
|
|
28
|
-
buffer.push(JSON.stringify(object));
|
|
29
|
-
} else if (Array.isArray(object)) {
|
|
30
|
-
buffer.push(LEFT_SQUARE_BRACKET);
|
|
31
|
-
let first = true;
|
|
32
|
-
object.forEach((element) => {
|
|
33
|
-
if (!first) {
|
|
34
|
-
buffer.push(COMMA);
|
|
35
|
-
}
|
|
36
|
-
first = false;
|
|
37
|
-
buffer.push(canonicalize(element));
|
|
38
|
-
});
|
|
39
|
-
buffer.push(RIGHT_SQUARE_BRACKET);
|
|
40
|
-
} else if (typeof object === "object") {
|
|
41
|
-
buffer.push(LEFT_CURLY_BRACKET);
|
|
42
|
-
let first = true;
|
|
43
|
-
Object.keys(object)
|
|
44
|
-
.sort()
|
|
45
|
-
.forEach((property) => {
|
|
46
|
-
if (!first) {
|
|
47
|
-
buffer.push(COMMA);
|
|
48
|
-
}
|
|
49
|
-
first = false;
|
|
50
|
-
buffer.push(canonicalizeString(property));
|
|
51
|
-
buffer.push(COLON);
|
|
52
|
-
// eslint-disable-next-line
|
|
53
|
-
buffer.push(canonicalize((object as any)[property])); // 'any' as a fallback
|
|
54
|
-
});
|
|
55
|
-
buffer.push(RIGHT_CURLY_BRACKET);
|
|
56
|
-
} else {
|
|
57
|
-
throw new TypeError("cannot encode " + object);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return buffer.join("");
|
|
61
|
-
}
|