@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/errors.ts
DELETED
|
@@ -1,82 +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
|
-
/**
|
|
18
|
-
* Base class for all verification errors
|
|
19
|
-
* Provides structured error handling with error codes
|
|
20
|
-
*/
|
|
21
|
-
export class VerificationError extends Error {
|
|
22
|
-
constructor(public code: string, message: string) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = 'VerificationError';
|
|
25
|
-
Object.setPrototypeOf(this, VerificationError.prototype);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Error thrown when timestamp verification fails
|
|
31
|
-
*/
|
|
32
|
-
export class TimestampError extends VerificationError {
|
|
33
|
-
constructor(message: string) {
|
|
34
|
-
super('TIMESTAMP_ERROR', message);
|
|
35
|
-
this.name = 'TimestampError';
|
|
36
|
-
Object.setPrototypeOf(this, TimestampError.prototype);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Error thrown when certificate verification fails
|
|
42
|
-
*/
|
|
43
|
-
export class CertificateError extends VerificationError {
|
|
44
|
-
constructor(message: string) {
|
|
45
|
-
super('CERTIFICATE_ERROR', message);
|
|
46
|
-
this.name = 'CertificateError';
|
|
47
|
-
Object.setPrototypeOf(this, CertificateError.prototype);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Error thrown when transparency log verification fails
|
|
53
|
-
*/
|
|
54
|
-
export class TLogError extends VerificationError {
|
|
55
|
-
constructor(message: string) {
|
|
56
|
-
super('TLOG_ERROR', message);
|
|
57
|
-
this.name = 'TLogError';
|
|
58
|
-
Object.setPrototypeOf(this, TLogError.prototype);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Error thrown when signature verification fails
|
|
64
|
-
*/
|
|
65
|
-
export class SignatureError extends VerificationError {
|
|
66
|
-
constructor(message: string) {
|
|
67
|
-
super('SIGNATURE_ERROR', message);
|
|
68
|
-
this.name = 'SignatureError';
|
|
69
|
-
Object.setPrototypeOf(this, SignatureError.prototype);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Error thrown when policy verification fails
|
|
75
|
-
*/
|
|
76
|
-
export class PolicyError extends VerificationError {
|
|
77
|
-
constructor(message: string) {
|
|
78
|
-
super('POLICY_ERROR', message);
|
|
79
|
-
this.name = 'PolicyError';
|
|
80
|
-
Object.setPrototypeOf(this, PolicyError.prototype);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import { describe, expect,it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { assertBundle } from "./bundle.js";
|
|
4
|
-
import { SigstoreVerifier } from "./sigstore.js";
|
|
5
|
-
import { X509Certificate } from "./x509/cert.js";
|
|
6
|
-
|
|
7
|
-
describe("Sigstore Browser Integration Tests", () => {
|
|
8
|
-
it("should initialize SigstoreVerifier in browser", () => {
|
|
9
|
-
const verifier = new SigstoreVerifier();
|
|
10
|
-
expect(verifier).toBeDefined();
|
|
11
|
-
expect(verifier).toBeInstanceOf(SigstoreVerifier);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("should have crypto.subtle available for ECDSA P-256 verification", async () => {
|
|
15
|
-
expect(globalThis.crypto).toBeDefined();
|
|
16
|
-
expect(globalThis.crypto.subtle).toBeDefined();
|
|
17
|
-
|
|
18
|
-
// Test ECDSA P-256 which is what Sigstore uses
|
|
19
|
-
const keyPair = await crypto.subtle.generateKey(
|
|
20
|
-
{
|
|
21
|
-
name: "ECDSA",
|
|
22
|
-
namedCurve: "P-256",
|
|
23
|
-
},
|
|
24
|
-
true,
|
|
25
|
-
["sign", "verify"]
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const data = new TextEncoder().encode("test");
|
|
29
|
-
const signature = await crypto.subtle.sign(
|
|
30
|
-
{ name: "ECDSA", hash: "SHA-256" },
|
|
31
|
-
keyPair.privateKey,
|
|
32
|
-
data
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const valid = await crypto.subtle.verify(
|
|
36
|
-
{ name: "ECDSA", hash: "SHA-256" },
|
|
37
|
-
keyPair.publicKey,
|
|
38
|
-
signature,
|
|
39
|
-
data
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
expect(valid).toBe(true);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should have crypto.subtle available for ECDSA P-384 verification", async () => {
|
|
46
|
-
// Test ECDSA P-384 which is also used by Sigstore
|
|
47
|
-
const keyPair = await crypto.subtle.generateKey(
|
|
48
|
-
{
|
|
49
|
-
name: "ECDSA",
|
|
50
|
-
namedCurve: "P-384",
|
|
51
|
-
},
|
|
52
|
-
true,
|
|
53
|
-
["sign", "verify"]
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const data = new TextEncoder().encode("test");
|
|
57
|
-
const signature = await crypto.subtle.sign(
|
|
58
|
-
{ name: "ECDSA", hash: "SHA-384" },
|
|
59
|
-
keyPair.privateKey,
|
|
60
|
-
data
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
const valid = await crypto.subtle.verify(
|
|
64
|
-
{ name: "ECDSA", hash: "SHA-384" },
|
|
65
|
-
keyPair.publicKey,
|
|
66
|
-
signature,
|
|
67
|
-
data
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
expect(valid).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("should support SHA-256 hashing in browser", async () => {
|
|
74
|
-
const data = new TextEncoder().encode("test data");
|
|
75
|
-
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
76
|
-
|
|
77
|
-
expect(hash).toBeInstanceOf(ArrayBuffer);
|
|
78
|
-
expect(hash.byteLength).toBe(32);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("should support SHA-384 hashing in browser", async () => {
|
|
82
|
-
const data = new TextEncoder().encode("test data");
|
|
83
|
-
const hash = await crypto.subtle.digest("SHA-384", data);
|
|
84
|
-
|
|
85
|
-
expect(hash).toBeInstanceOf(ArrayBuffer);
|
|
86
|
-
expect(hash.byteLength).toBe(48);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("should support SHA-512 hashing in browser", async () => {
|
|
90
|
-
const data = new TextEncoder().encode("test data");
|
|
91
|
-
const hash = await crypto.subtle.digest("SHA-512", data);
|
|
92
|
-
|
|
93
|
-
expect(hash).toBeInstanceOf(ArrayBuffer);
|
|
94
|
-
expect(hash.byteLength).toBe(64);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("should support X.509 certificate key import (SPKI format)", async () => {
|
|
98
|
-
const keyPair = await crypto.subtle.generateKey(
|
|
99
|
-
{
|
|
100
|
-
name: "ECDSA",
|
|
101
|
-
namedCurve: "P-256",
|
|
102
|
-
},
|
|
103
|
-
true,
|
|
104
|
-
["sign", "verify"]
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const exported = await crypto.subtle.exportKey("spki", keyPair.publicKey);
|
|
108
|
-
const imported = await crypto.subtle.importKey(
|
|
109
|
-
"spki",
|
|
110
|
-
exported,
|
|
111
|
-
{ name: "ECDSA", namedCurve: "P-256" },
|
|
112
|
-
true,
|
|
113
|
-
["verify"]
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
expect(imported).toBeDefined();
|
|
117
|
-
expect(imported.type).toBe("public");
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should support RSA-PSS for signature verification", async () => {
|
|
121
|
-
const keyPair = await crypto.subtle.generateKey(
|
|
122
|
-
{
|
|
123
|
-
name: "RSA-PSS",
|
|
124
|
-
modulusLength: 2048,
|
|
125
|
-
publicExponent: new Uint8Array([1, 0, 1]),
|
|
126
|
-
hash: "SHA-256",
|
|
127
|
-
},
|
|
128
|
-
true,
|
|
129
|
-
["sign", "verify"]
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const data = new TextEncoder().encode("test");
|
|
133
|
-
const signature = await crypto.subtle.sign(
|
|
134
|
-
{
|
|
135
|
-
name: "RSA-PSS",
|
|
136
|
-
saltLength: 32,
|
|
137
|
-
},
|
|
138
|
-
keyPair.privateKey,
|
|
139
|
-
data
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const valid = await crypto.subtle.verify(
|
|
143
|
-
{
|
|
144
|
-
name: "RSA-PSS",
|
|
145
|
-
saltLength: 32,
|
|
146
|
-
},
|
|
147
|
-
keyPair.publicKey,
|
|
148
|
-
signature,
|
|
149
|
-
data
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
expect(valid).toBe(true);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("should verify RSA-PSS signed X.509 certificate", async () => {
|
|
156
|
-
// Self-signed certificate with standard RSA key but RSA-PSS signature (SHA-256, salt=32)
|
|
157
|
-
// WebCrypto requires rsaEncryption OID for the public key, not id-RSASSA-PSS
|
|
158
|
-
const rsaPssCertPem = `-----BEGIN CERTIFICATE-----
|
|
159
|
-
MIIDhTCCAjmgAwIBAgIUYzfguLRx71Cbn2Ty7xCt3GH+N6AwQQYJKoZIhvcNAQEK
|
|
160
|
-
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
|
|
161
|
-
AKIDAgEgMB4xHDAaBgNVBAMME1Rlc3QgUlNBLVBTUyBTaWduZWQwHhcNMjUxMTMw
|
|
162
|
-
MDMwMDU2WhcNMjYxMTMwMDMwMDU2WjAeMRwwGgYDVQQDDBNUZXN0IFJTQS1QU1Mg
|
|
163
|
-
U2lnbmVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA29B/88QFBILg
|
|
164
|
-
YCWp1pF3xBj7FVhBUCv6JwyZAouYWUxgGmpFg6RLgbaWk59oDtEFQ5xRGSDXLuMW
|
|
165
|
-
GL5wZVCjSnmYcBsBDROO+HfLKwDRcHw09bJY979PDHPy5EPZale/JsdxE+fepUw1
|
|
166
|
-
XQDvlK5Dyp6WKl9UBjTtl6+LHKV/KTo+SiaQP2vsbZvTIt3s8MHybV/ixYXlSPQt
|
|
167
|
-
Kju50REAaqSSYqxNzsq8Z2sjJbFBcatt5C1JhfoSyIHz5D0slriv8835DYhk0u4n
|
|
168
|
-
bvNzXhWeF7htHTiPWCYwaTr5cgjyhEWg3SNP+Tu9dxCYVXm7/jWTHRdPqUPQqFsq
|
|
169
|
-
wXqsrzSP+wIDAQABo1MwUTAdBgNVHQ4EFgQU+UcBxKusOtY4lSjqyFuxQfN5zdIw
|
|
170
|
-
HwYDVR0jBBgwFoAU+UcBxKusOtY4lSjqyFuxQfN5zdIwDwYDVR0TAQH/BAUwAwEB
|
|
171
|
-
/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEI
|
|
172
|
-
MA0GCWCGSAFlAwQCAQUAogMCASADggEBAFIn3VpfydVvpI82NwfeGxWlhZhgD2dX
|
|
173
|
-
gJUhj6pcXqwnlCzpyRI4e3uNO1h9nr9UrogI0AV2IDhVdUYxz3F2/680JtxXpB1x
|
|
174
|
-
J02BSAYllvXgf9efc20lFzbPDzvMzKnwx3S3proewbJ4uVPHzvKubWsx8MwEuI0X
|
|
175
|
-
8xkI1qMIXgevTCt+LGhp+0C/u8WsW3or5ZI7GnZNowPJEAtZnfO+VORB7FvbzEGr
|
|
176
|
-
ewS+2T7Qz4oXaQMidPOjr1Q8WKqaKO4yCtC8cz4qVWi3lNqAcAGtonQMXUiflEWV
|
|
177
|
-
9kqKQx+LJYJqxKkBtDRnRLnVNn4+inotrgnV126LsCe3uLaGwJIFy1U=
|
|
178
|
-
-----END CERTIFICATE-----`;
|
|
179
|
-
|
|
180
|
-
const cert = X509Certificate.parse(rsaPssCertPem);
|
|
181
|
-
|
|
182
|
-
// Verify it's an RSA-PSS certificate
|
|
183
|
-
expect(cert.signatureAlgorithmOid).toBe("1.2.840.113549.1.1.10");
|
|
184
|
-
expect(cert.signatureAlgorithm).toBe("sha256");
|
|
185
|
-
|
|
186
|
-
// Verify the self-signed certificate (signature verification)
|
|
187
|
-
const valid = await cert.verify();
|
|
188
|
-
expect(valid).toBe(true);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("should support TextEncoder/TextDecoder for UTF-8", () => {
|
|
192
|
-
const encoder = new TextEncoder();
|
|
193
|
-
const decoder = new TextDecoder();
|
|
194
|
-
|
|
195
|
-
const text = "Hello Sigstore 🔐";
|
|
196
|
-
const encoded = encoder.encode(text);
|
|
197
|
-
const decoded = decoder.decode(encoded);
|
|
198
|
-
|
|
199
|
-
expect(decoded).toBe(text);
|
|
200
|
-
expect(encoded).toBeInstanceOf(Uint8Array);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("should support base64 encoding/decoding (atob/btoa)", () => {
|
|
204
|
-
const text = "Hello Sigstore";
|
|
205
|
-
const base64 = btoa(text);
|
|
206
|
-
const decoded = atob(base64);
|
|
207
|
-
|
|
208
|
-
expect(decoded).toBe(text);
|
|
209
|
-
expect(base64).toBe("SGVsbG8gU2lnc3RvcmU=");
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it("should support Uint8Array operations", () => {
|
|
213
|
-
const arr1 = new Uint8Array([1, 2, 3, 4, 5]);
|
|
214
|
-
const arr2 = new Uint8Array([6, 7, 8, 9, 10]);
|
|
215
|
-
|
|
216
|
-
const combined = new Uint8Array(arr1.length + arr2.length);
|
|
217
|
-
combined.set(arr1, 0);
|
|
218
|
-
combined.set(arr2, arr1.length);
|
|
219
|
-
|
|
220
|
-
expect(combined.length).toBe(10);
|
|
221
|
-
expect(combined[0]).toBe(1);
|
|
222
|
-
expect(combined[5]).toBe(6);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it("should support ArrayBuffer operations", () => {
|
|
226
|
-
const buffer = new ArrayBuffer(32);
|
|
227
|
-
const view = new Uint8Array(buffer);
|
|
228
|
-
|
|
229
|
-
view[0] = 255;
|
|
230
|
-
view[31] = 128;
|
|
231
|
-
|
|
232
|
-
expect(buffer.byteLength).toBe(32);
|
|
233
|
-
expect(view[0]).toBe(255);
|
|
234
|
-
expect(view[31]).toBe(128);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it("should support DataView for byte manipulation", () => {
|
|
238
|
-
const buffer = new ArrayBuffer(8);
|
|
239
|
-
const view = new DataView(buffer);
|
|
240
|
-
|
|
241
|
-
view.setUint32(0, 0x12345678, false); // big-endian
|
|
242
|
-
view.setUint32(4, 0x9abcdef0, false);
|
|
243
|
-
|
|
244
|
-
expect(view.getUint32(0, false)).toBe(0x12345678);
|
|
245
|
-
expect(view.getUint8(0)).toBe(0x12);
|
|
246
|
-
expect(view.getUint8(1)).toBe(0x34);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it("should support JSON parsing of complex structures", () => {
|
|
250
|
-
const json = '{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.3","verificationMaterial":{"tlogEntries":[{"logIndex":"123"}]}}';
|
|
251
|
-
const parsed = JSON.parse(json);
|
|
252
|
-
|
|
253
|
-
expect(parsed.mediaType).toBeDefined();
|
|
254
|
-
expect(parsed.verificationMaterial).toBeDefined();
|
|
255
|
-
expect(parsed.verificationMaterial.tlogEntries).toBeInstanceOf(Array);
|
|
256
|
-
expect(parsed.verificationMaterial.tlogEntries[0].logIndex).toBe("123");
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
describe("Bundle structural validation", () => {
|
|
261
|
-
const entry = {
|
|
262
|
-
logIndex: "1",
|
|
263
|
-
logId: { keyId: "AA==" },
|
|
264
|
-
kindVersion: { kind: "dsse", version: "0.0.1" },
|
|
265
|
-
integratedTime: "1",
|
|
266
|
-
inclusionPromise: { signedEntryTimestamp: "AA==" },
|
|
267
|
-
canonicalizedBody: "e30=",
|
|
268
|
-
};
|
|
269
|
-
const bundle = () => structuredClone({
|
|
270
|
-
mediaType: "application/vnd.dev.sigstore.bundle.v0.3+json",
|
|
271
|
-
verificationMaterial: { certificate: { rawBytes: "AA==" }, tlogEntries: [entry] },
|
|
272
|
-
dsseEnvelope: { payload: "AA==", payloadType: "t", signatures: [{ sig: "AA==" }] },
|
|
273
|
-
});
|
|
274
|
-
const rejects = (mutate: (b: ReturnType<typeof bundle>) => void, message: string) => {
|
|
275
|
-
const b = bundle();
|
|
276
|
-
mutate(b);
|
|
277
|
-
expect(() => assertBundle(b)).toThrow(message);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
it("accepts a well-formed bundle", () => {
|
|
281
|
-
expect(() => assertBundle(bundle())).not.toThrow();
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("rejects malformed fields, empty promises and missing integrated times", () => {
|
|
285
|
-
rejects((b) => { b.verificationMaterial.tlogEntries = []; }, "tlogEntries");
|
|
286
|
-
rejects((b) => { (b.verificationMaterial.tlogEntries[0] as Record<string, unknown>).logIndex = 1; }, "tlog entry");
|
|
287
|
-
rejects((b) => { (b.verificationMaterial.tlogEntries[0] as Record<string, unknown>).integratedTime = 1; }, "integratedTime");
|
|
288
|
-
rejects((b) => { b.verificationMaterial.tlogEntries[0].inclusionPromise.signedEntryTimestamp = ""; }, "inclusion promise");
|
|
289
|
-
rejects((b) => { (b.verificationMaterial.tlogEntries[0] as Record<string, unknown>).integratedTime = null; }, "inclusion promise");
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it("caps entries at 32", () => {
|
|
293
|
-
rejects((b) => { b.verificationMaterial.tlogEntries = Array(33).fill(entry); }, "tlogEntries");
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it("requires exactly one signature source with exactly one signature", () => {
|
|
297
|
-
rejects((b) => { (b as Record<string, unknown>).messageSignature = { messageDigest: { algorithm: "SHA2_256", digest: "AA==" }, signature: "AA==" }; }, "exactly one of");
|
|
298
|
-
rejects((b) => { delete (b as Partial<ReturnType<typeof bundle>>).dsseEnvelope; }, "exactly one of");
|
|
299
|
-
rejects((b) => { b.dsseEnvelope.signatures.push({ sig: "AA==" }); }, "exactly one signature");
|
|
300
|
-
});
|
|
301
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
export { SigstoreVerifier } from "./sigstore.js";
|
|
2
|
-
export type { SigstoreVerifierOptions } from "./sigstore.js";
|
|
3
|
-
export type { SigstoreBundle, TLogEntry, VerificationMaterial, MessageSignature, TimestampVerificationData, RFC3161Timestamp } from "./bundle.js";
|
|
4
|
-
export type { TrustedRoot, Sigstore, RawTimestampAuthority } from "./interfaces.js";
|
|
5
|
-
export {
|
|
6
|
-
VerificationError,
|
|
7
|
-
TimestampError,
|
|
8
|
-
CertificateError,
|
|
9
|
-
TLogError,
|
|
10
|
-
SignatureError,
|
|
11
|
-
PolicyError,
|
|
12
|
-
} from "./errors.js";
|
|
13
|
-
export { verifyRFC3161Timestamp, verifyBundleTimestamp } from "./timestamp/tsa.js";
|
|
14
|
-
export { TrustedRootProvider, type TrustedRootProviderOptions } from "./trust/tuf.js";
|
|
15
|
-
export {
|
|
16
|
-
X509Certificate,
|
|
17
|
-
EXTENSION_OID_SCT,
|
|
18
|
-
EXTENSION_OID_FULCIO_ISSUER_V1,
|
|
19
|
-
EXTENSION_OID_GITHUB_WORKFLOW_TRIGGER,
|
|
20
|
-
EXTENSION_OID_GITHUB_WORKFLOW_SHA,
|
|
21
|
-
EXTENSION_OID_GITHUB_WORKFLOW_NAME,
|
|
22
|
-
EXTENSION_OID_GITHUB_WORKFLOW_REPOSITORY,
|
|
23
|
-
EXTENSION_OID_GITHUB_WORKFLOW_REF,
|
|
24
|
-
EXTENSION_OID_OTHERNAME,
|
|
25
|
-
EXTENSION_OID_FULCIO_ISSUER_V2,
|
|
26
|
-
EXTENSION_OID_BUILD_SIGNER_URI,
|
|
27
|
-
EXTENSION_OID_BUILD_SIGNER_DIGEST,
|
|
28
|
-
EXTENSION_OID_RUNNER_ENVIRONMENT,
|
|
29
|
-
EXTENSION_OID_SOURCE_REPOSITORY_URI,
|
|
30
|
-
EXTENSION_OID_SOURCE_REPOSITORY_DIGEST,
|
|
31
|
-
EXTENSION_OID_SOURCE_REPOSITORY_REF,
|
|
32
|
-
EXTENSION_OID_SOURCE_REPOSITORY_IDENTIFIER,
|
|
33
|
-
EXTENSION_OID_SOURCE_REPOSITORY_OWNER_URI,
|
|
34
|
-
EXTENSION_OID_SOURCE_REPOSITORY_OWNER_IDENTIFIER,
|
|
35
|
-
EXTENSION_OID_BUILD_CONFIG_URI,
|
|
36
|
-
EXTENSION_OID_BUILD_CONFIG_DIGEST,
|
|
37
|
-
EXTENSION_OID_BUILD_TRIGGER,
|
|
38
|
-
EXTENSION_OID_RUN_INVOCATION_URI,
|
|
39
|
-
EXTENSION_OID_SOURCE_REPOSITORY_VISIBILITY,
|
|
40
|
-
} from "./x509/cert.js";
|
|
41
|
-
export {
|
|
42
|
-
X509Extension,
|
|
43
|
-
X509FulcioIssuerV1,
|
|
44
|
-
X509FulcioIssuerV2,
|
|
45
|
-
X509GitHubWorkflowTriggerExtension,
|
|
46
|
-
X509GitHubWorkflowSHAExtension,
|
|
47
|
-
X509GitHubWorkflowNameExtension,
|
|
48
|
-
X509GitHubWorkflowRepositoryExtension,
|
|
49
|
-
X509GitHubWorkflowRefExtension,
|
|
50
|
-
X509BuildSignerURIExtension,
|
|
51
|
-
X509BuildSignerDigestExtension,
|
|
52
|
-
X509RunnerEnvironmentExtension,
|
|
53
|
-
X509SourceRepositoryURIExtension,
|
|
54
|
-
X509SourceRepositoryDigestExtension,
|
|
55
|
-
X509SourceRepositoryRefExtension,
|
|
56
|
-
X509SourceRepositoryIdentifierExtension,
|
|
57
|
-
X509SourceRepositoryOwnerURIExtension,
|
|
58
|
-
X509SourceRepositoryOwnerIdentifierExtension,
|
|
59
|
-
X509BuildConfigURIExtension,
|
|
60
|
-
X509BuildConfigDigestExtension,
|
|
61
|
-
X509BuildTriggerExtension,
|
|
62
|
-
X509RunInvocationURIExtension,
|
|
63
|
-
X509SourceRepositoryVisibilityExtension,
|
|
64
|
-
} from "./x509/ext.js";
|
|
65
|
-
export { CertificateChainVerifier } from "./x509/chain.js";
|
|
66
|
-
export {
|
|
67
|
-
GITHUB_OIDC_ISSUER,
|
|
68
|
-
OIDCIssuer,
|
|
69
|
-
OIDCIssuerV2,
|
|
70
|
-
GitHubWorkflowTrigger,
|
|
71
|
-
GitHubWorkflowSHA,
|
|
72
|
-
GitHubWorkflowName,
|
|
73
|
-
GitHubWorkflowRepository,
|
|
74
|
-
GitHubWorkflowRef,
|
|
75
|
-
OIDCBuildSignerURI,
|
|
76
|
-
OIDCBuildSignerDigest,
|
|
77
|
-
OIDCRunnerEnvironment,
|
|
78
|
-
OIDCSourceRepositoryURI,
|
|
79
|
-
OIDCSourceRepositoryDigest,
|
|
80
|
-
OIDCSourceRepositoryRef,
|
|
81
|
-
OIDCSourceRepositoryIdentifier,
|
|
82
|
-
OIDCSourceRepositoryOwnerURI,
|
|
83
|
-
OIDCSourceRepositoryOwnerIdentifier,
|
|
84
|
-
OIDCBuildConfigURI,
|
|
85
|
-
OIDCBuildConfigDigest,
|
|
86
|
-
OIDCBuildTrigger,
|
|
87
|
-
OIDCRunInvocationURI,
|
|
88
|
-
OIDCSourceRepositoryVisibility,
|
|
89
|
-
AllOf,
|
|
90
|
-
AnyOf,
|
|
91
|
-
Identity,
|
|
92
|
-
} from "./policy.js";
|
|
93
|
-
export type { VerificationPolicy } from "./policy.js";
|
package/src/interfaces.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { X509Certificate } from "./x509/index.js";
|
|
2
|
-
|
|
3
|
-
export function parseValidityPeriod(
|
|
4
|
-
validity: { start?: unknown; end?: unknown } | undefined,
|
|
5
|
-
): { start: Date; end: Date } {
|
|
6
|
-
if (
|
|
7
|
-
typeof validity?.start !== "string" ||
|
|
8
|
-
(validity.end !== undefined && typeof validity.end !== "string")
|
|
9
|
-
) {
|
|
10
|
-
throw new Error("Invalid authority validity period");
|
|
11
|
-
}
|
|
12
|
-
const start = new Date(validity.start);
|
|
13
|
-
const end = validity.end === undefined
|
|
14
|
-
? new Date(8640000000000000)
|
|
15
|
-
: new Date(validity.end);
|
|
16
|
-
if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime()) || start > end) {
|
|
17
|
-
throw new Error("Invalid authority validity period");
|
|
18
|
-
}
|
|
19
|
-
return { start, end };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export enum SigstoreRoots {
|
|
23
|
-
certificateAuthorities = "certificateAuthorities",
|
|
24
|
-
ctlogs = "ctlogs",
|
|
25
|
-
timestampAuthorities = "timestampAuthorities",
|
|
26
|
-
tlogs = "tlogs",
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export type RawTimestampAuthorities = RawTimestampAuthority[];
|
|
30
|
-
|
|
31
|
-
export interface TrustedRoot {
|
|
32
|
-
mediaType: string;
|
|
33
|
-
tlogs: RawLogs;
|
|
34
|
-
certificateAuthorities: RawCAs;
|
|
35
|
-
ctlogs: RawLogs;
|
|
36
|
-
timestampAuthorities: RawTimestampAuthorities;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface RawTimestampAuthority {
|
|
40
|
-
subject: {
|
|
41
|
-
organization: string;
|
|
42
|
-
commonName: string;
|
|
43
|
-
};
|
|
44
|
-
certChain: {
|
|
45
|
-
certificates: {
|
|
46
|
-
rawBytes: string;
|
|
47
|
-
}[];
|
|
48
|
-
};
|
|
49
|
-
validFor: {
|
|
50
|
-
start: string;
|
|
51
|
-
end?: string;
|
|
52
|
-
};
|
|
53
|
-
operator?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface CTLog {
|
|
57
|
-
logID: Uint8Array;
|
|
58
|
-
publicKey: CryptoKey;
|
|
59
|
-
operator: string;
|
|
60
|
-
validFor: {
|
|
61
|
-
start: Date;
|
|
62
|
-
end: Date;
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface RekorKeyInfo {
|
|
67
|
-
publicKey: CryptoKey;
|
|
68
|
-
logId: Uint8Array;
|
|
69
|
-
hashAlgorithm: string;
|
|
70
|
-
operator: string;
|
|
71
|
-
validFor: {
|
|
72
|
-
start: Date;
|
|
73
|
-
end: Date;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface CertAuthority {
|
|
78
|
-
certChain: X509Certificate[];
|
|
79
|
-
validFor: {
|
|
80
|
-
start: Date;
|
|
81
|
-
end: Date;
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface Sigstore {
|
|
86
|
-
rekor: RekorKeyInfo[];
|
|
87
|
-
ctlogs: CTLog[];
|
|
88
|
-
certificateAuthorities: CertAuthority[];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface RawLog {
|
|
92
|
-
baseUrl: string;
|
|
93
|
-
hashAlgorithm: string;
|
|
94
|
-
publicKey: {
|
|
95
|
-
rawBytes: string;
|
|
96
|
-
keyDetails: string;
|
|
97
|
-
validFor: {
|
|
98
|
-
start: string;
|
|
99
|
-
end?: string;
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
logId: {
|
|
103
|
-
keyId: string;
|
|
104
|
-
};
|
|
105
|
-
operator?: string;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export type RawLogs = RawLog[];
|
|
109
|
-
|
|
110
|
-
export interface RawCA {
|
|
111
|
-
subject: {
|
|
112
|
-
organization: string;
|
|
113
|
-
commonName: string;
|
|
114
|
-
};
|
|
115
|
-
uri: string;
|
|
116
|
-
certChain: {
|
|
117
|
-
certificates: {
|
|
118
|
-
rawBytes: string;
|
|
119
|
-
}[];
|
|
120
|
-
};
|
|
121
|
-
validFor: {
|
|
122
|
-
start: string;
|
|
123
|
-
end?: string;
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export type RawCAs = RawCA[];
|
|
128
|
-
|
|
129
|
-
// Re-export crypto enums from crypto-browser (shared with tuf-browser)
|
|
130
|
-
export { KeyTypes, EcdsaTypes, HashAlgorithms } from "@freedomofpress/crypto-browser";
|
|
131
|
-
import { HashAlgorithms } from "@freedomofpress/crypto-browser";
|
|
132
|
-
|
|
133
|
-
// Supported hash algorithms for payload hash validation
|
|
134
|
-
// Rekor v1 uses lowercase (sha256), Rekor v2 uses uppercase with underscore (SHA2_256)
|
|
135
|
-
const SUPPORTED_HASH_ALGORITHMS: Record<string, string> = {
|
|
136
|
-
"sha256": HashAlgorithms.SHA256,
|
|
137
|
-
"sha384": HashAlgorithms.SHA384,
|
|
138
|
-
"sha512": HashAlgorithms.SHA512,
|
|
139
|
-
"SHA2_256": HashAlgorithms.SHA256,
|
|
140
|
-
"SHA2_384": HashAlgorithms.SHA384,
|
|
141
|
-
"SHA2_512": HashAlgorithms.SHA512,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export function getHashAlgorithm(algorithm: string): string {
|
|
145
|
-
const hashAlg = SUPPORTED_HASH_ALGORITHMS[algorithm];
|
|
146
|
-
if (!hashAlg) {
|
|
147
|
-
throw new Error(`Unsupported hash algorithm: ${algorithm}`);
|
|
148
|
-
}
|
|
149
|
-
return hashAlg;
|
|
150
|
-
}
|
package/src/oid.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// From https://github.com/sigstore/sigstore-js/blob/main/packages/core/src/oid.ts
|
|
2
|
-
|
|
3
|
-
export const ECDSA_SIGNATURE_ALGOS: Record<string, string> = {
|
|
4
|
-
"1.2.840.10045.4.3.1": "sha224",
|
|
5
|
-
"1.2.840.10045.4.3.2": "sha256",
|
|
6
|
-
"1.2.840.10045.4.3.3": "sha384",
|
|
7
|
-
"1.2.840.10045.4.3.4": "sha512",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// RSA signature algorithms (PKCS#1 v1.5)
|
|
11
|
-
export const RSA_SIGNATURE_ALGOS: Record<string, string> = {
|
|
12
|
-
"1.2.840.113549.1.1.11": "sha256", // sha256WithRSAEncryption
|
|
13
|
-
"1.2.840.113549.1.1.12": "sha384", // sha384WithRSAEncryption
|
|
14
|
-
"1.2.840.113549.1.1.13": "sha512", // sha512WithRSAEncryption
|
|
15
|
-
"1.2.840.113549.1.1.5": "sha1", // sha1WithRSAEncryption
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// RSASSA-PSS OID - hash algorithm must be parsed from signature algorithm parameters
|
|
19
|
-
export const OID_RSASSA_PSS = "1.2.840.113549.1.1.10";
|
|
20
|
-
|
|
21
|
-
export const SHA2_HASH_ALGOS: Record<string, string> = {
|
|
22
|
-
"2.16.840.1.101.3.4.2.1": "sha256",
|
|
23
|
-
"2.16.840.1.101.3.4.2.2": "sha384",
|
|
24
|
-
"2.16.840.1.101.3.4.2.3": "sha512",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Default hash algorithm used when not specified
|
|
28
|
-
export const DEFAULT_HASH_ALGORITHM = "sha256";
|
|
29
|
-
|
|
30
|
-
export const ECDSA_CURVE_NAMES: Record<string, string> = {
|
|
31
|
-
"1.2.840.10045.3.1.7": "secp256r1",
|
|
32
|
-
"1.3.132.0.34": "secp384r1",
|
|
33
|
-
"1.3.132.0.35": "secp521r1",
|
|
34
|
-
};
|