@freedomofpress/sigstore-browser 0.1.15 → 0.1.16
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/bundle.d.ts +2 -3
- package/dist/bundle.js.map +1 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js.map +1 -1
- package/dist/dsse.d.ts +0 -1
- package/dist/dsse.js.map +1 -1
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +9 -10
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +1 -2
- package/dist/interfaces.js +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/oid.d.ts +0 -1
- package/dist/oid.js.map +1 -1
- package/dist/policy.d.ts +0 -1
- package/dist/policy.js +1 -1
- package/dist/policy.js.map +1 -1
- package/dist/rfc3161/error.d.ts +0 -1
- package/dist/rfc3161/error.js.map +1 -1
- package/dist/rfc3161/index.d.ts +0 -1
- package/dist/rfc3161/index.js.map +1 -1
- package/dist/rfc3161/timestamp.d.ts +0 -1
- package/dist/rfc3161/timestamp.js.map +1 -1
- package/dist/rfc3161/tstinfo.d.ts +0 -1
- package/dist/rfc3161/tstinfo.js.map +1 -1
- package/dist/sigstore.d.ts +2 -3
- package/dist/sigstore.js +9 -9
- package/dist/sigstore.js.map +1 -1
- package/dist/timestamp/tsa.d.ts +1 -2
- package/dist/timestamp/tsa.js +1 -1
- package/dist/timestamp/tsa.js.map +1 -1
- package/dist/tlog/body.d.ts +0 -1
- package/dist/tlog/body.js +1 -1
- package/dist/tlog/body.js.map +1 -1
- package/dist/tlog/checkpoint.d.ts +0 -1
- package/dist/tlog/checkpoint.js.map +1 -1
- package/dist/tlog/dsse.d.ts +0 -1
- package/dist/tlog/dsse.js +3 -0
- package/dist/tlog/dsse.js.map +1 -1
- package/dist/tlog/hashedrekord.d.ts +0 -1
- package/dist/tlog/hashedrekord.js.map +1 -1
- package/dist/tlog/intoto.d.ts +0 -1
- package/dist/tlog/intoto.js.map +1 -1
- package/dist/tlog/merkle.d.ts +0 -1
- package/dist/tlog/merkle.js.map +1 -1
- package/dist/trust/tuf-root.d.ts +0 -1
- package/dist/trust/tuf-root.js.map +1 -1
- package/dist/trust/tuf.d.ts +0 -1
- package/dist/trust/tuf.js.map +1 -1
- package/dist/x509/cert.d.ts +0 -1
- package/dist/x509/cert.js +1 -1
- package/dist/x509/cert.js.map +1 -1
- package/dist/x509/chain.d.ts +0 -1
- package/dist/x509/chain.js +2 -2
- package/dist/x509/chain.js.map +1 -1
- package/dist/x509/ext.d.ts +0 -1
- package/dist/x509/ext.js.map +1 -1
- package/dist/x509/index.d.ts +1 -2
- package/dist/x509/index.js +1 -1
- package/dist/x509/index.js.map +1 -1
- package/dist/x509/sct.d.ts +0 -1
- package/dist/x509/sct.js.map +1 -1
- package/package.json +15 -8
- package/.github/workflows/conformance.yml +0 -29
- package/.github/workflows/publish.yml +0 -47
- package/dist/bundle.d.ts.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/dsse.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/interfaces.d.ts.map +0 -1
- package/dist/oid.d.ts.map +0 -1
- package/dist/policy.d.ts.map +0 -1
- package/dist/rfc3161/error.d.ts.map +0 -1
- package/dist/rfc3161/index.d.ts.map +0 -1
- package/dist/rfc3161/timestamp.d.ts.map +0 -1
- package/dist/rfc3161/tstinfo.d.ts.map +0 -1
- package/dist/sigstore.d.ts.map +0 -1
- package/dist/timestamp/tsa.d.ts.map +0 -1
- package/dist/tlog/body.d.ts.map +0 -1
- package/dist/tlog/checkpoint.d.ts.map +0 -1
- package/dist/tlog/dsse.d.ts.map +0 -1
- package/dist/tlog/hashedrekord.d.ts.map +0 -1
- package/dist/tlog/intoto.d.ts.map +0 -1
- package/dist/tlog/merkle.d.ts.map +0 -1
- package/dist/trust/tuf-root.d.ts.map +0 -1
- package/dist/trust/tuf.d.ts.map +0 -1
- package/dist/x509/cert.d.ts.map +0 -1
- package/dist/x509/chain.d.ts.map +0 -1
- package/dist/x509/ext.d.ts.map +0 -1
- package/dist/x509/index.d.ts.map +0 -1
- package/dist/x509/sct.d.ts.map +0 -1
- package/eslint.config.mjs +0 -31
- package/src/bundle.ts +0 -186
- package/src/cli.ts +0 -290
- package/src/dsse.ts +0 -49
- package/src/ed25519.browser.test.ts +0 -76
- package/src/errors.ts +0 -82
- package/src/index.browser.test.ts +0 -301
- package/src/index.ts +0 -93
- package/src/interfaces.ts +0 -150
- package/src/oid.ts +0 -34
- package/src/policy.ts +0 -476
- package/src/rfc3161/error.ts +0 -16
- package/src/rfc3161/index.ts +0 -17
- package/src/rfc3161/timestamp.ts +0 -268
- package/src/rfc3161/tstinfo.ts +0 -78
- package/src/security.browser.test.ts +0 -249
- package/src/sigstore.ts +0 -605
- package/src/timestamp/tsa.ts +0 -212
- package/src/tlog/body.ts +0 -84
- package/src/tlog/checkpoint.ts +0 -154
- package/src/tlog/dsse.ts +0 -153
- package/src/tlog/hashedrekord.ts +0 -136
- package/src/tlog/intoto.ts +0 -109
- package/src/tlog/merkle.ts +0 -152
- package/src/trust/README.md +0 -38
- package/src/trust/tuf-root.ts +0 -3
- package/src/trust/tuf.ts +0 -233
- package/src/verify.browser.test.ts +0 -281
- package/src/x509/cert.ts +0 -569
- package/src/x509/chain.ts +0 -212
- package/src/x509/ext.ts +0 -356
- package/src/x509/index.ts +0 -19
- package/src/x509/sct.ts +0 -156
- package/test/fixtures/rekor2.ts +0 -14
- package/test/fixtures/sigstore.ts +0 -13
- package/tsconfig.json +0 -18
- package/vite.config.playwright.ts +0 -14
- package/vite.config.ts +0 -18
package/src/x509/cert.ts
DELETED
|
@@ -1,569 +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 {
|
|
17
|
-
ASN1Obj,
|
|
18
|
-
importKey,
|
|
19
|
-
toDER,
|
|
20
|
-
Uint8ArrayToBase64,
|
|
21
|
-
uint8ArrayEqual,
|
|
22
|
-
verifySignature,
|
|
23
|
-
} from "@freedomofpress/crypto-browser";
|
|
24
|
-
import { KeyTypes } from "../interfaces.js";
|
|
25
|
-
import { DEFAULT_HASH_ALGORITHM, ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, OID_RSASSA_PSS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from "../oid.js";
|
|
26
|
-
import {
|
|
27
|
-
X509AuthorityKeyIDExtension,
|
|
28
|
-
X509BasicConstraintsExtension,
|
|
29
|
-
X509BuildConfigDigestExtension,
|
|
30
|
-
X509BuildConfigURIExtension,
|
|
31
|
-
X509BuildSignerDigestExtension,
|
|
32
|
-
X509BuildSignerURIExtension,
|
|
33
|
-
X509BuildTriggerExtension,
|
|
34
|
-
X509Extension,
|
|
35
|
-
X509FulcioIssuerV1,
|
|
36
|
-
X509FulcioIssuerV2,
|
|
37
|
-
X509GitHubWorkflowNameExtension,
|
|
38
|
-
X509GitHubWorkflowRefExtension,
|
|
39
|
-
X509GitHubWorkflowRepositoryExtension,
|
|
40
|
-
X509GitHubWorkflowSHAExtension,
|
|
41
|
-
X509GitHubWorkflowTriggerExtension,
|
|
42
|
-
X509KeyUsageExtension,
|
|
43
|
-
X509RunInvocationURIExtension,
|
|
44
|
-
X509RunnerEnvironmentExtension,
|
|
45
|
-
X509SCTExtension,
|
|
46
|
-
X509SourceRepositoryDigestExtension,
|
|
47
|
-
X509SourceRepositoryIdentifierExtension,
|
|
48
|
-
X509SourceRepositoryOwnerIdentifierExtension,
|
|
49
|
-
X509SourceRepositoryOwnerURIExtension,
|
|
50
|
-
X509SourceRepositoryRefExtension,
|
|
51
|
-
X509SourceRepositoryURIExtension,
|
|
52
|
-
X509SourceRepositoryVisibilityExtension,
|
|
53
|
-
X509SubjectAlternativeNameExtension,
|
|
54
|
-
X509SubjectKeyIDExtension,
|
|
55
|
-
} from "./ext.js";
|
|
56
|
-
|
|
57
|
-
// Standard X.509 extension OIDs
|
|
58
|
-
const EXTENSION_OID_SUBJECT_KEY_ID = "2.5.29.14";
|
|
59
|
-
const EXTENSION_OID_KEY_USAGE = "2.5.29.15";
|
|
60
|
-
const EXTENSION_OID_SUBJECT_ALT_NAME = "2.5.29.17";
|
|
61
|
-
const EXTENSION_OID_BASIC_CONSTRAINTS = "2.5.29.19";
|
|
62
|
-
const EXTENSION_OID_AUTHORITY_KEY_ID = "2.5.29.35";
|
|
63
|
-
|
|
64
|
-
// CT Log SCT extension OID
|
|
65
|
-
export const EXTENSION_OID_SCT = "1.3.6.1.4.1.11129.2.4.2";
|
|
66
|
-
|
|
67
|
-
// Distinguished Name attribute OIDs (X.500)
|
|
68
|
-
const DN_OID_COMMON_NAME = "2.5.4.3";
|
|
69
|
-
const DN_OID_COUNTRY = "2.5.4.6";
|
|
70
|
-
const DN_OID_LOCALITY = "2.5.4.7";
|
|
71
|
-
const DN_OID_STATE = "2.5.4.8";
|
|
72
|
-
const DN_OID_ORGANIZATION = "2.5.4.10";
|
|
73
|
-
const DN_OID_ORGANIZATIONAL_UNIT = "2.5.4.11";
|
|
74
|
-
|
|
75
|
-
const DN_OID_TO_NAME: Record<string, string> = {
|
|
76
|
-
[DN_OID_COMMON_NAME]: "CN",
|
|
77
|
-
[DN_OID_COUNTRY]: "C",
|
|
78
|
-
[DN_OID_LOCALITY]: "L",
|
|
79
|
-
[DN_OID_STATE]: "ST",
|
|
80
|
-
[DN_OID_ORGANIZATION]: "O",
|
|
81
|
-
[DN_OID_ORGANIZATIONAL_UNIT]: "OU",
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// Fulcio extension OIDs
|
|
85
|
-
// https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md
|
|
86
|
-
export const EXTENSION_OID_FULCIO_ISSUER_V1 = "1.3.6.1.4.1.57264.1.1";
|
|
87
|
-
export const EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER = "1.3.6.1.4.1.57264.1.2";
|
|
88
|
-
export const EXTENSION_OID_GITHUB_WORKFLOW_SHA = "1.3.6.1.4.1.57264.1.3";
|
|
89
|
-
export const EXTENSION_OID_GITHUB_WORKFLOW_NAME = "1.3.6.1.4.1.57264.1.4";
|
|
90
|
-
export const EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY = "1.3.6.1.4.1.57264.1.5";
|
|
91
|
-
export const EXTENSION_OID_GITHUB_WORKFLOW_REF = "1.3.6.1.4.1.57264.1.6";
|
|
92
|
-
export const EXTENSION_OID_OTHERNAME = "1.3.6.1.4.1.57264.1.7";
|
|
93
|
-
export const EXTENSION_OID_FULCIO_ISSUER_V2 = "1.3.6.1.4.1.57264.1.8";
|
|
94
|
-
export const EXTENSION_OID_BUILD_SIGNER_URI = "1.3.6.1.4.1.57264.1.9";
|
|
95
|
-
export const EXTENSION_OID_BUILD_SIGNER_DIGEST = "1.3.6.1.4.1.57264.1.10";
|
|
96
|
-
export const EXTENSION_OID_RUNNER_ENVIRONMENT = "1.3.6.1.4.1.57264.1.11";
|
|
97
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_URI = "1.3.6.1.4.1.57264.1.12";
|
|
98
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_DIGEST = "1.3.6.1.4.1.57264.1.13";
|
|
99
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_REF = "1.3.6.1.4.1.57264.1.14";
|
|
100
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER = "1.3.6.1.4.1.57264.1.15";
|
|
101
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI = "1.3.6.1.4.1.57264.1.16";
|
|
102
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER = "1.3.6.1.4.1.57264.1.17";
|
|
103
|
-
export const EXTENSION_OID_BUILD_CONFIG_URI = "1.3.6.1.4.1.57264.1.18";
|
|
104
|
-
export const EXTENSION_OID_BUILD_CONFIG_DIGEST = "1.3.6.1.4.1.57264.1.19";
|
|
105
|
-
export const EXTENSION_OID_BUILD_TRIGGER = "1.3.6.1.4.1.57264.1.20";
|
|
106
|
-
export const EXTENSION_OID_RUN_INVOCATION_URI = "1.3.6.1.4.1.57264.1.21";
|
|
107
|
-
export const EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY = "1.3.6.1.4.1.57264.1.22";
|
|
108
|
-
|
|
109
|
-
export class X509Certificate {
|
|
110
|
-
public root: ASN1Obj;
|
|
111
|
-
|
|
112
|
-
constructor(asn1: ASN1Obj) {
|
|
113
|
-
this.root = asn1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
public static parse(cert: Uint8Array | string): X509Certificate {
|
|
117
|
-
const der = typeof cert === "string" ? toDER(cert) : cert;
|
|
118
|
-
const asn1 = ASN1Obj.parseBuffer(der);
|
|
119
|
-
return new X509Certificate(asn1);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
get tbsCertificate(): ASN1Obj {
|
|
123
|
-
return this.tbsCertificateObj;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get version(): string {
|
|
127
|
-
// version number is the first element of the version context specific tag
|
|
128
|
-
const ver = this.versionObj.subs[0].toInteger();
|
|
129
|
-
return `v${(ver + BigInt(1)).toString()}`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
get serialNumber(): Uint8Array {
|
|
133
|
-
return this.serialNumberObj.value;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
get notBefore(): Date {
|
|
137
|
-
// notBefore is the first element of the validity sequence
|
|
138
|
-
return this.validityObj.subs[0].toDate();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
get notAfter(): Date {
|
|
142
|
-
// notAfter is the second element of the validity sequence
|
|
143
|
-
return this.validityObj.subs[1].toDate();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get issuer(): Uint8Array {
|
|
147
|
-
return this.issuerObj.value;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
get subject(): Uint8Array {
|
|
151
|
-
return this.subjectObj.value;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Returns the issuer distinguished name as a Map of attribute names to values.
|
|
156
|
-
* Common attributes: CN (Common Name), O (Organization), L (Locality),
|
|
157
|
-
* ST (State), C (Country), OU (Organizational Unit)
|
|
158
|
-
*/
|
|
159
|
-
get issuerDN(): Map<string, string> {
|
|
160
|
-
return this.parseDistinguishedName(this.issuerObj);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Returns the subject distinguished name as a Map of attribute names to values.
|
|
165
|
-
* Common attributes: CN (Common Name), O (Organization), L (Locality),
|
|
166
|
-
* ST (State), C (Country), OU (Organizational Unit)
|
|
167
|
-
*/
|
|
168
|
-
get subjectDN(): Map<string, string> {
|
|
169
|
-
return this.parseDistinguishedName(this.subjectObj);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
get publicKey(): Uint8Array {
|
|
173
|
-
return this.subjectPublicKeyInfoObj.toDER();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Import the public key with a specific hash algorithm and signature scheme for RSA keys.
|
|
178
|
-
* For ECDSA keys, both parameters are ignored.
|
|
179
|
-
* @param hashAlg - Hash algorithm (e.g., "sha384") for RSA keys
|
|
180
|
-
* @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5
|
|
181
|
-
*/
|
|
182
|
-
public async getPublicKeyObj(hashAlg?: string, usePss?: boolean): Promise<CryptoKey> {
|
|
183
|
-
const publicKey = this.subjectPublicKeyInfoObj.toDER();
|
|
184
|
-
const spki = ASN1Obj.parseBuffer(publicKey);
|
|
185
|
-
const algorithmOID = spki.subs[0].subs[0].toOID();
|
|
186
|
-
|
|
187
|
-
// RSA key (OID 1.2.840.113549.1.1.1) or RSA-PSS key (OID 1.2.840.113549.1.1.10)
|
|
188
|
-
const isRsaKey = algorithmOID === "1.2.840.113549.1.1.1";
|
|
189
|
-
const isRsaPssKey = algorithmOID === OID_RSASSA_PSS;
|
|
190
|
-
|
|
191
|
-
if (isRsaPssKey) {
|
|
192
|
-
// WebCrypto doesn't support importing keys with id-RSASSA-PSS OID, only rsaEncryption
|
|
193
|
-
throw new Error(
|
|
194
|
-
"RSA-PSS public keys (id-RSASSA-PSS OID) are not supported by WebCrypto. " +
|
|
195
|
-
"Only certificates with standard RSA keys (rsaEncryption OID) signed using RSA-PSS are supported."
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (isRsaKey) {
|
|
200
|
-
const hash = hashAlg || DEFAULT_HASH_ALGORITHM;
|
|
201
|
-
// crypto-browser extracts hash from scheme and uses PSS unless "PKCS1" is present
|
|
202
|
-
const scheme = usePss ? hash : `PKCS1_${hash}`;
|
|
203
|
-
return importKey(KeyTypes.RSA, scheme, Uint8ArrayToBase64(publicKey));
|
|
204
|
-
} else {
|
|
205
|
-
// ECDSA key - the curve OID is in the second element
|
|
206
|
-
const curveOID = spki.subs[0].subs[1]?.toOID();
|
|
207
|
-
const curve = ECDSA_CURVE_NAMES[curveOID];
|
|
208
|
-
if (!curve) {
|
|
209
|
-
throw new Error(`Unknown ECDSA curve OID: ${curveOID}`);
|
|
210
|
-
}
|
|
211
|
-
return importKey(KeyTypes.Ecdsa, curve, Uint8ArrayToBase64(publicKey));
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
get publicKeyObj(): Promise<CryptoKey> {
|
|
216
|
-
return this.getPublicKeyObj();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
get signatureAlgorithm(): string {
|
|
220
|
-
const oid: string = this.signatureAlgorithmObj.subs[0].toOID();
|
|
221
|
-
return ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid] || this.parseRsaPssHashAlgorithm();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
get signatureAlgorithmOid(): string {
|
|
225
|
-
return this.signatureAlgorithmObj.subs[0].toOID();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Parse hash algorithm from RSA-PSS signature algorithm parameters.
|
|
230
|
-
* RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }
|
|
231
|
-
*/
|
|
232
|
-
private parseRsaPssHashAlgorithm(): string {
|
|
233
|
-
const sigAlgOid = this.signatureAlgorithmObj.subs[0].toOID();
|
|
234
|
-
if (sigAlgOid !== OID_RSASSA_PSS) {
|
|
235
|
-
return "";
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// RSA-PSS has parameters in the second element of the signature algorithm sequence
|
|
239
|
-
const params = this.signatureAlgorithmObj.subs[1];
|
|
240
|
-
if (!params || params.subs.length === 0) {
|
|
241
|
-
return DEFAULT_HASH_ALGORITHM;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// First element is hashAlgorithm [0] EXPLICIT
|
|
245
|
-
const hashAlgWrapper = params.subs[0];
|
|
246
|
-
if (hashAlgWrapper && hashAlgWrapper.subs.length > 0) {
|
|
247
|
-
// The wrapper contains a SEQUENCE with the hash algorithm OID
|
|
248
|
-
const hashAlgSeq = hashAlgWrapper.subs[0];
|
|
249
|
-
if (hashAlgSeq && hashAlgSeq.subs.length > 0) {
|
|
250
|
-
const hashOid = hashAlgSeq.subs[0].toOID();
|
|
251
|
-
return SHA2_HASH_ALGOS[hashOid] || DEFAULT_HASH_ALGORITHM;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return DEFAULT_HASH_ALGORITHM;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
get signatureValue(): Uint8Array {
|
|
259
|
-
// Signature value is a bit string, so we need to skip the first byte
|
|
260
|
-
return this.signatureValueObj.value.subarray(1);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
get subjectAltName(): string | undefined {
|
|
264
|
-
const ext = this.extSubjectAltName;
|
|
265
|
-
return ext?.uri || ext?.rfc822Name;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
get extensions(): ASN1Obj[] {
|
|
269
|
-
// The extension list is the first (and only) element of the extensions
|
|
270
|
-
// context specific tag
|
|
271
|
-
const extSeq = this.extensionsObj?.subs[0];
|
|
272
|
-
return extSeq?.subs || /* istanbul ignore next */ [];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
get extKeyUsage(): X509KeyUsageExtension | undefined {
|
|
276
|
-
const ext = this.findExtension(EXTENSION_OID_KEY_USAGE);
|
|
277
|
-
return ext ? new X509KeyUsageExtension(ext) : undefined;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
get extBasicConstraints(): X509BasicConstraintsExtension | undefined {
|
|
281
|
-
const ext = this.findExtension(EXTENSION_OID_BASIC_CONSTRAINTS);
|
|
282
|
-
return ext ? new X509BasicConstraintsExtension(ext) : undefined;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
get extSubjectAltName(): X509SubjectAlternativeNameExtension | undefined {
|
|
286
|
-
const ext = this.findExtension(EXTENSION_OID_SUBJECT_ALT_NAME);
|
|
287
|
-
return ext ? new X509SubjectAlternativeNameExtension(ext) : undefined;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
get extAuthorityKeyID(): X509AuthorityKeyIDExtension | undefined {
|
|
291
|
-
const ext = this.findExtension(EXTENSION_OID_AUTHORITY_KEY_ID);
|
|
292
|
-
return ext ? new X509AuthorityKeyIDExtension(ext) : undefined;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
get extSubjectKeyID(): X509SubjectKeyIDExtension | undefined {
|
|
296
|
-
const ext = this.findExtension(EXTENSION_OID_SUBJECT_KEY_ID);
|
|
297
|
-
return ext
|
|
298
|
-
? new X509SubjectKeyIDExtension(ext)
|
|
299
|
-
: /* istanbul ignore next */ undefined;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
get extSCT(): X509SCTExtension | undefined {
|
|
303
|
-
const ext = this.findExtension(EXTENSION_OID_SCT);
|
|
304
|
-
return ext ? new X509SCTExtension(ext) : undefined;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
get extFulcioIssuerV1(): X509FulcioIssuerV1 | undefined {
|
|
308
|
-
const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V1);
|
|
309
|
-
return ext ? new X509FulcioIssuerV1(ext) : undefined;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
get extFulcioIssuerV2(): X509FulcioIssuerV2 | undefined {
|
|
313
|
-
const ext = this.findExtension(EXTENSION_OID_FULCIO_ISSUER_V2);
|
|
314
|
-
return ext ? new X509FulcioIssuerV2(ext) : undefined;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
get extGitHubWorkflowTrigger(): X509GitHubWorkflowTriggerExtension | undefined {
|
|
318
|
-
const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER);
|
|
319
|
-
return ext ? new X509GitHubWorkflowTriggerExtension(ext) : undefined;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
get extGitHubWorkflowSHA(): X509GitHubWorkflowSHAExtension | undefined {
|
|
323
|
-
const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_SHA);
|
|
324
|
-
return ext ? new X509GitHubWorkflowSHAExtension(ext) : undefined;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
get extGitHubWorkflowName(): X509GitHubWorkflowNameExtension | undefined {
|
|
328
|
-
const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_NAME);
|
|
329
|
-
return ext ? new X509GitHubWorkflowNameExtension(ext) : undefined;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
get extGitHubWorkflowRepository(): X509GitHubWorkflowRepositoryExtension | undefined {
|
|
333
|
-
const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY);
|
|
334
|
-
return ext ? new X509GitHubWorkflowRepositoryExtension(ext) : undefined;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
get extGitHubWorkflowRef(): X509GitHubWorkflowRefExtension | undefined {
|
|
338
|
-
const ext = this.findExtension(EXTENSION_OID_GITHUB_WORKFLOW_REF);
|
|
339
|
-
return ext ? new X509GitHubWorkflowRefExtension(ext) : undefined;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
get extBuildSignerURI(): X509BuildSignerURIExtension | undefined {
|
|
343
|
-
const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_URI);
|
|
344
|
-
return ext ? new X509BuildSignerURIExtension(ext) : undefined;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
get extBuildSignerDigest(): X509BuildSignerDigestExtension | undefined {
|
|
348
|
-
const ext = this.findExtension(EXTENSION_OID_BUILD_SIGNER_DIGEST);
|
|
349
|
-
return ext ? new X509BuildSignerDigestExtension(ext) : undefined;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
get extRunnerEnvironment(): X509RunnerEnvironmentExtension | undefined {
|
|
353
|
-
const ext = this.findExtension(EXTENSION_OID_RUNNER_ENVIRONMENT);
|
|
354
|
-
return ext ? new X509RunnerEnvironmentExtension(ext) : undefined;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
get extSourceRepositoryURI(): X509SourceRepositoryURIExtension | undefined {
|
|
358
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_URI);
|
|
359
|
-
return ext ? new X509SourceRepositoryURIExtension(ext) : undefined;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
get extSourceRepositoryDigest(): X509SourceRepositoryDigestExtension | undefined {
|
|
363
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_DIGEST);
|
|
364
|
-
return ext ? new X509SourceRepositoryDigestExtension(ext) : undefined;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
get extSourceRepositoryRef(): X509SourceRepositoryRefExtension | undefined {
|
|
368
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_REF);
|
|
369
|
-
return ext ? new X509SourceRepositoryRefExtension(ext) : undefined;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
get extSourceRepositoryIdentifier(): X509SourceRepositoryIdentifierExtension | undefined {
|
|
373
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER);
|
|
374
|
-
return ext ? new X509SourceRepositoryIdentifierExtension(ext) : undefined;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
get extSourceRepositoryOwnerURI(): X509SourceRepositoryOwnerURIExtension | undefined {
|
|
378
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI);
|
|
379
|
-
return ext ? new X509SourceRepositoryOwnerURIExtension(ext) : undefined;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
get extSourceRepositoryOwnerIdentifier(): X509SourceRepositoryOwnerIdentifierExtension | undefined {
|
|
383
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER);
|
|
384
|
-
return ext ? new X509SourceRepositoryOwnerIdentifierExtension(ext) : undefined;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
get extBuildConfigURI(): X509BuildConfigURIExtension | undefined {
|
|
388
|
-
const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_URI);
|
|
389
|
-
return ext ? new X509BuildConfigURIExtension(ext) : undefined;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
get extBuildConfigDigest(): X509BuildConfigDigestExtension | undefined {
|
|
393
|
-
const ext = this.findExtension(EXTENSION_OID_BUILD_CONFIG_DIGEST);
|
|
394
|
-
return ext ? new X509BuildConfigDigestExtension(ext) : undefined;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
get extBuildTrigger(): X509BuildTriggerExtension | undefined {
|
|
398
|
-
const ext = this.findExtension(EXTENSION_OID_BUILD_TRIGGER);
|
|
399
|
-
return ext ? new X509BuildTriggerExtension(ext) : undefined;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
get extRunInvocationURI(): X509RunInvocationURIExtension | undefined {
|
|
403
|
-
const ext = this.findExtension(EXTENSION_OID_RUN_INVOCATION_URI);
|
|
404
|
-
return ext ? new X509RunInvocationURIExtension(ext) : undefined;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
get extSourceRepositoryVisibility(): X509SourceRepositoryVisibilityExtension | undefined {
|
|
408
|
-
const ext = this.findExtension(EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY);
|
|
409
|
-
return ext ? new X509SourceRepositoryVisibilityExtension(ext) : undefined;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
get isCA(): boolean {
|
|
413
|
-
const ca = this.extBasicConstraints?.isCA || false;
|
|
414
|
-
|
|
415
|
-
// If the KeyUsage extension is present, keyCertSign must be set
|
|
416
|
-
if (this.extKeyUsage) {
|
|
417
|
-
return ca && this.extKeyUsage.keyCertSign;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return ca;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
public extension(oid: string): X509Extension | undefined {
|
|
424
|
-
const ext = this.findExtension(oid);
|
|
425
|
-
return ext ? new X509Extension(ext) : undefined;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
public async verify(issuerCertificate?: X509Certificate): Promise<boolean> {
|
|
429
|
-
// Extract the hash algorithm from this certificate's signature algorithm
|
|
430
|
-
const sigAlgOID = this.signatureAlgorithmOid;
|
|
431
|
-
const isRsaPss = sigAlgOID === OID_RSASSA_PSS;
|
|
432
|
-
|
|
433
|
-
// Get hash algorithm - for RSA-PSS, parse from parameters; otherwise lookup in tables
|
|
434
|
-
const hashAlg = isRsaPss
|
|
435
|
-
? this.parseRsaPssHashAlgorithm()
|
|
436
|
-
: (RSA_SIGNATURE_ALGOS[sigAlgOID] || ECDSA_SIGNATURE_ALGOS[sigAlgOID]);
|
|
437
|
-
|
|
438
|
-
// Use the issuer's public key if provided, otherwise use the subject's (for self-signed certs)
|
|
439
|
-
// Import with the correct hash algorithm and key type for this certificate's signature
|
|
440
|
-
const publicKeyObj = issuerCertificate
|
|
441
|
-
? await issuerCertificate.getPublicKeyObj(hashAlg, isRsaPss)
|
|
442
|
-
: await this.getPublicKeyObj(hashAlg, isRsaPss);
|
|
443
|
-
|
|
444
|
-
return await verifySignature(
|
|
445
|
-
publicKeyObj,
|
|
446
|
-
this.tbsCertificate.toDER(),
|
|
447
|
-
this.signatureValue,
|
|
448
|
-
this.signatureAlgorithm,
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
public validForDate(date: Date): boolean {
|
|
453
|
-
return this.notBefore <= date && date <= this.notAfter;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
public equals(other: X509Certificate): boolean {
|
|
457
|
-
return uint8ArrayEqual(this.root.toDER(), other.root.toDER());
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Creates a copy of the certificate with a new buffer
|
|
461
|
-
public clone(): X509Certificate {
|
|
462
|
-
const der = this.root.toDER();
|
|
463
|
-
const clone = new Uint8Array(der);
|
|
464
|
-
return X509Certificate.parse(clone);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
private findExtension(oid: string): ASN1Obj | undefined {
|
|
468
|
-
// Find the extension with the given OID. The OID will always be the first
|
|
469
|
-
// element of the extension sequence
|
|
470
|
-
return this.extensions.find((ext) => ext.subs[0].toOID() === oid);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/////////////////////////////////////////////////////////////////////////////
|
|
474
|
-
// The following properties use the documented x509 structure to locate the
|
|
475
|
-
// desired ASN.1 object
|
|
476
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1
|
|
477
|
-
|
|
478
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.1
|
|
479
|
-
private get tbsCertificateObj(): ASN1Obj {
|
|
480
|
-
// tbsCertificate is the first element of the certificate sequence
|
|
481
|
-
return this.root.subs[0];
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2
|
|
485
|
-
private get signatureAlgorithmObj(): ASN1Obj {
|
|
486
|
-
// signatureAlgorithm is the second element of the certificate sequence
|
|
487
|
-
return this.root.subs[1];
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.3
|
|
491
|
-
private get signatureValueObj(): ASN1Obj {
|
|
492
|
-
// signatureValue is the third element of the certificate sequence
|
|
493
|
-
return this.root.subs[2];
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1
|
|
497
|
-
private get versionObj(): ASN1Obj {
|
|
498
|
-
// version is the first element of the tbsCertificate sequence
|
|
499
|
-
return this.tbsCertificateObj.subs[0];
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2
|
|
503
|
-
private get serialNumberObj(): ASN1Obj {
|
|
504
|
-
// serialNumber is the second element of the tbsCertificate sequence
|
|
505
|
-
return this.tbsCertificateObj.subs[1];
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.4
|
|
509
|
-
private get issuerObj(): ASN1Obj {
|
|
510
|
-
// issuer is the fourth element of the tbsCertificate sequence
|
|
511
|
-
return this.tbsCertificateObj.subs[3];
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5
|
|
515
|
-
private get validityObj(): ASN1Obj {
|
|
516
|
-
// version is the fifth element of the tbsCertificate sequence
|
|
517
|
-
return this.tbsCertificateObj.subs[4];
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.6
|
|
521
|
-
private get subjectObj(): ASN1Obj {
|
|
522
|
-
// subject is the sixth element of the tbsCertificate sequence
|
|
523
|
-
return this.tbsCertificateObj.subs[5];
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7
|
|
527
|
-
private get subjectPublicKeyInfoObj(): ASN1Obj {
|
|
528
|
-
// subjectPublicKeyInfo is the seventh element of the tbsCertificate sequence
|
|
529
|
-
return this.tbsCertificateObj.subs[6];
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Extensions can't be located by index because their position varies. Instead,
|
|
533
|
-
// we need to find the extensions context specific tag
|
|
534
|
-
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.9
|
|
535
|
-
private get extensionsObj(): ASN1Obj | undefined {
|
|
536
|
-
return this.tbsCertificateObj.subs.find((sub) =>
|
|
537
|
-
sub.tag.isContextSpecific(0x03),
|
|
538
|
-
);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Parse a Distinguished Name (issuer or subject) ASN1Obj into a Map
|
|
542
|
-
// DN structure: SEQUENCE of SET of SEQUENCE (AttributeTypeAndValue)
|
|
543
|
-
// Each AttributeTypeAndValue is [OID, value]
|
|
544
|
-
private parseDistinguishedName(dnObj: ASN1Obj): Map<string, string> {
|
|
545
|
-
const result = new Map<string, string>();
|
|
546
|
-
|
|
547
|
-
// Iterate over RDNs (RelativeDistinguishedName - each is a SET)
|
|
548
|
-
for (const rdn of dnObj.subs) {
|
|
549
|
-
// Each RDN contains one or more AttributeTypeAndValue (SEQUENCE)
|
|
550
|
-
for (const atv of rdn.subs) {
|
|
551
|
-
if (atv.subs.length >= 2) {
|
|
552
|
-
const oidObj = atv.subs[0];
|
|
553
|
-
const valueObj = atv.subs[1];
|
|
554
|
-
|
|
555
|
-
if (oidObj.tag.isOID()) {
|
|
556
|
-
const oid = oidObj.toOID();
|
|
557
|
-
const attrName = DN_OID_TO_NAME[oid];
|
|
558
|
-
if (attrName) {
|
|
559
|
-
const value = new TextDecoder().decode(valueObj.value);
|
|
560
|
-
result.set(attrName, value);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
return result;
|
|
568
|
-
}
|
|
569
|
-
}
|