@freedomofpress/sigstore-browser 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +3 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/interfaces.d.ts +1 -15
  8. package/dist/interfaces.d.ts.map +1 -1
  9. package/dist/interfaces.js +2 -18
  10. package/dist/interfaces.js.map +1 -1
  11. package/dist/rfc3161/timestamp.d.ts +1 -1
  12. package/dist/rfc3161/timestamp.d.ts.map +1 -1
  13. package/dist/rfc3161/timestamp.js +3 -5
  14. package/dist/rfc3161/timestamp.js.map +1 -1
  15. package/dist/rfc3161/tstinfo.d.ts +1 -1
  16. package/dist/rfc3161/tstinfo.d.ts.map +1 -1
  17. package/dist/rfc3161/tstinfo.js +18 -4
  18. package/dist/rfc3161/tstinfo.js.map +1 -1
  19. package/dist/sigstore.d.ts +1 -1
  20. package/dist/sigstore.d.ts.map +1 -1
  21. package/dist/sigstore.js +6 -8
  22. package/dist/sigstore.js.map +1 -1
  23. package/dist/timestamp/tsa.d.ts +1 -1
  24. package/dist/timestamp/tsa.d.ts.map +1 -1
  25. package/dist/timestamp/tsa.js +4 -5
  26. package/dist/timestamp/tsa.js.map +1 -1
  27. package/dist/tlog/body.js +1 -1
  28. package/dist/tlog/body.js.map +1 -1
  29. package/dist/tlog/checkpoint.d.ts.map +1 -1
  30. package/dist/tlog/checkpoint.js +6 -7
  31. package/dist/tlog/checkpoint.js.map +1 -1
  32. package/dist/tlog/dsse.js +3 -3
  33. package/dist/tlog/dsse.js.map +1 -1
  34. package/dist/tlog/hashedrekord.js +1 -1
  35. package/dist/tlog/hashedrekord.js.map +1 -1
  36. package/dist/tlog/intoto.js +2 -2
  37. package/dist/tlog/intoto.js.map +1 -1
  38. package/dist/tlog/merkle.js +4 -4
  39. package/dist/tlog/merkle.js.map +1 -1
  40. package/dist/trust/tuf.d.ts +1 -1
  41. package/dist/trust/tuf.d.ts.map +1 -1
  42. package/dist/trust/tuf.js +4 -4
  43. package/dist/trust/tuf.js.map +1 -1
  44. package/dist/x509/cert.d.ts +1 -1
  45. package/dist/x509/cert.d.ts.map +1 -1
  46. package/dist/x509/cert.js +4 -7
  47. package/dist/x509/cert.js.map +1 -1
  48. package/dist/x509/chain.d.ts.map +1 -1
  49. package/dist/x509/chain.js +16 -5
  50. package/dist/x509/chain.js.map +1 -1
  51. package/dist/x509/ext.d.ts +1 -1
  52. package/dist/x509/ext.d.ts.map +1 -1
  53. package/dist/x509/ext.js +17 -3
  54. package/dist/x509/ext.js.map +1 -1
  55. package/dist/x509/sct.d.ts.map +1 -1
  56. package/dist/x509/sct.js +2 -4
  57. package/dist/x509/sct.js.map +1 -1
  58. package/package.json +8 -4
  59. package/src/cli.ts +6 -1
  60. package/src/index.ts +3 -0
  61. package/src/interfaces.ts +2 -17
  62. package/src/rfc3161/timestamp.ts +3 -5
  63. package/src/rfc3161/tstinfo.ts +3 -5
  64. package/src/sigstore.ts +17 -16
  65. package/src/timestamp/tsa.ts +5 -6
  66. package/src/tlog/body.ts +1 -1
  67. package/src/tlog/checkpoint.ts +13 -7
  68. package/src/tlog/dsse.ts +3 -3
  69. package/src/tlog/hashedrekord.ts +1 -1
  70. package/src/tlog/intoto.ts +2 -2
  71. package/src/tlog/merkle.ts +4 -4
  72. package/src/trust/tuf.ts +6 -6
  73. package/src/x509/cert.ts +11 -7
  74. package/src/x509/chain.ts +6 -6
  75. package/src/x509/ext.ts +2 -4
  76. package/src/x509/sct.ts +2 -4
  77. package/vite.config.playwright.ts +4 -16
  78. package/dist/asn1/error.d.ts +0 -5
  79. package/dist/asn1/error.d.ts.map +0 -1
  80. package/dist/asn1/error.js +0 -20
  81. package/dist/asn1/error.js.map +0 -1
  82. package/dist/asn1/index.d.ts +0 -2
  83. package/dist/asn1/index.d.ts.map +0 -1
  84. package/dist/asn1/index.js +0 -17
  85. package/dist/asn1/index.js.map +0 -1
  86. package/dist/asn1/length.d.ts +0 -4
  87. package/dist/asn1/length.d.ts.map +0 -1
  88. package/dist/asn1/length.js +0 -59
  89. package/dist/asn1/length.js.map +0 -1
  90. package/dist/asn1/obj.d.ts +0 -15
  91. package/dist/asn1/obj.d.ts.map +0 -1
  92. package/dist/asn1/obj.js +0 -153
  93. package/dist/asn1/obj.js.map +0 -1
  94. package/dist/asn1/parse.d.ts +0 -7
  95. package/dist/asn1/parse.d.ts.map +0 -1
  96. package/dist/asn1/parse.js +0 -118
  97. package/dist/asn1/parse.js.map +0 -1
  98. package/dist/asn1/tag.d.ts +0 -17
  99. package/dist/asn1/tag.d.ts.map +0 -1
  100. package/dist/asn1/tag.js +0 -86
  101. package/dist/asn1/tag.js.map +0 -1
  102. package/dist/canonicalize.d.ts +0 -2
  103. package/dist/canonicalize.d.ts.map +0 -1
  104. package/dist/canonicalize.js +0 -64
  105. package/dist/canonicalize.js.map +0 -1
  106. package/dist/crypto.d.ts +0 -5
  107. package/dist/crypto.d.ts.map +0 -1
  108. package/dist/crypto.js +0 -260
  109. package/dist/crypto.js.map +0 -1
  110. package/dist/encoding.d.ts +0 -17
  111. package/dist/encoding.d.ts.map +0 -1
  112. package/dist/encoding.js +0 -112
  113. package/dist/encoding.js.map +0 -1
  114. package/dist/pem.d.ts +0 -3
  115. package/dist/pem.d.ts.map +0 -1
  116. package/dist/pem.js +0 -41
  117. package/dist/pem.js.map +0 -1
  118. package/dist/stream.d.ts +0 -22
  119. package/dist/stream.d.ts.map +0 -1
  120. package/dist/stream.js +0 -114
  121. package/dist/stream.js.map +0 -1
  122. package/src/asn1/error.ts +0 -18
  123. package/src/asn1/index.ts +0 -16
  124. package/src/asn1/length.ts +0 -71
  125. package/src/asn1/obj.ts +0 -184
  126. package/src/asn1/parse.ts +0 -146
  127. package/src/asn1/tag.ts +0 -105
  128. package/src/canonicalize.ts +0 -61
  129. package/src/crypto.ts +0 -310
  130. package/src/encoding.ts +0 -141
  131. package/src/pem.ts +0 -48
  132. package/src/stream.ts +0 -141
  133. package/src/types/tuf-browser.d.ts +0 -13
package/src/interfaces.ts CHANGED
@@ -99,20 +99,5 @@ export interface RawCA {
99
99
 
100
100
  export type RawCAs = RawCA[];
101
101
 
102
- export enum KeyTypes {
103
- Ecdsa = "ECDSA",
104
- Ed25519 = "Ed25519",
105
- RSA = "RSA",
106
- }
107
-
108
- export enum EcdsaTypes {
109
- P256 = "P-256",
110
- P384 = "P-384",
111
- P521 = "P-521",
112
- }
113
-
114
- export enum HashAlgorithms {
115
- SHA256 = "SHA-256",
116
- SHA384 = "SHA-384",
117
- SHA512 = "SHA-512",
118
- }
102
+ // Re-export crypto enums from crypto-browser (shared with tuf-browser)
103
+ export { KeyTypes, EcdsaTypes, HashAlgorithms } from "@freedomofpress/crypto-browser";
@@ -13,9 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
- import { ASN1Obj } from "../asn1/index.js";
17
- import { bufferEqual, verifySignature } from "../crypto.js";
18
- import { toArrayBuffer } from "../encoding.js";
16
+ import { ASN1Obj, uint8ArrayEqual, verifySignature } from "@freedomofpress/crypto-browser";
19
17
  import { HashAlgorithms } from "../interfaces.js";
20
18
  import { ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from "../oid.js";
21
19
  import { RFC3161TimestampVerificationError } from "./error.js";
@@ -123,11 +121,11 @@ export class RFC3161Timestamp {
123
121
 
124
122
  const tstInfoDigest = await crypto.subtle.digest(
125
123
  hashAlgName,
126
- toArrayBuffer(this.tstInfo.raw),
124
+ this.tstInfo.raw as Uint8Array<ArrayBuffer>,
127
125
  );
128
126
  const expectedDigest = this.messageDigestAttributeObj.subs[1].subs[0].value;
129
127
 
130
- if (!bufferEqual(new Uint8Array(tstInfoDigest), expectedDigest)) {
128
+ if (!uint8ArrayEqual(new Uint8Array(tstInfoDigest), expectedDigest)) {
131
129
  throw new RFC3161TimestampVerificationError(
132
130
  "signed data does not match tstInfo",
133
131
  );
@@ -13,9 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
- import { ASN1Obj } from "../asn1/index.js";
17
- import { bufferEqual } from "../crypto.js";
18
- import { toArrayBuffer } from "../encoding.js";
16
+ import { ASN1Obj, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
19
17
  import { HashAlgorithms } from "../interfaces.js";
20
18
  import { SHA2_HASH_ALGOS } from "../oid.js";
21
19
  import { RFC3161TimestampVerificationError } from "./error.js";
@@ -62,10 +60,10 @@ export class TSTInfo {
62
60
 
63
61
  const digest = await crypto.subtle.digest(
64
62
  hashAlgName,
65
- toArrayBuffer(data),
63
+ data as Uint8Array<ArrayBuffer>,
66
64
  );
67
65
  if (
68
- !bufferEqual(new Uint8Array(digest), this.messageImprintHashedMessage)
66
+ !uint8ArrayEqual(new Uint8Array(digest), this.messageImprintHashedMessage)
69
67
  ) {
70
68
  throw new RFC3161TimestampVerificationError(
71
69
  "message imprint does not match artifact",
package/src/sigstore.ts CHANGED
@@ -1,19 +1,27 @@
1
- import { SigstoreBundle } from "./bundle.js";
2
- import { canonicalize } from "./canonicalize.js";
3
- import { importKey, verifySignature, verifySignatureOverDigest } from "./crypto.js";
4
- import { preAuthEncoding } from "./dsse.js";
5
1
  import {
6
2
  base64ToUint8Array,
3
+ ByteStream,
4
+ canonicalize,
5
+ importKey,
7
6
  stringToUint8Array,
8
- toArrayBuffer,
9
7
  uint8ArrayEqual,
10
8
  Uint8ArrayToHex,
11
9
  Uint8ArrayToString,
12
- } from "./encoding.js";
10
+ verifySignature,
11
+ verifySignatureOverDigest,
12
+ } from "@freedomofpress/crypto-browser";
13
+ import { HashAlgorithms } from "./interfaces.js";
14
+ import {
15
+ CertificateChainVerifier,
16
+ EXTENSION_OID_SCT,
17
+ X509Certificate,
18
+ X509SCTExtension,
19
+ } from "./x509/index.js";
20
+ import { SigstoreBundle } from "./bundle.js";
21
+ import { preAuthEncoding } from "./dsse.js";
13
22
  import {
14
23
  CertAuthority,
15
24
  CTLog,
16
- HashAlgorithms,
17
25
  RawCAs,
18
26
  RawLogs,
19
27
  RawTimestampAuthorities,
@@ -22,13 +30,6 @@ import {
22
30
  SigstoreRoots,
23
31
  TrustedRoot,
24
32
  } from "./interfaces.js";
25
- import { ByteStream } from "./stream.js";
26
- import {
27
- CertificateChainVerifier,
28
- EXTENSION_OID_SCT,
29
- X509Certificate,
30
- X509SCTExtension,
31
- } from "./x509/index.js";
32
33
  import { verifyMerkleInclusion } from "./tlog/merkle.js";
33
34
  import { verifyCheckpoint } from "./tlog/checkpoint.js";
34
35
  import { verifyTLogBody } from "./tlog/body.js";
@@ -302,7 +303,7 @@ export class SigstoreVerifier {
302
303
 
303
304
  // Calculate hash of the issuer's public key
304
305
  const issuerId = new Uint8Array(
305
- await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(issuer.publicKey)),
306
+ await crypto.subtle.digest(HashAlgorithms.SHA256, issuer.publicKey as Uint8Array<ArrayBuffer>),
306
307
  );
307
308
  preCert.appendView(issuerId);
308
309
 
@@ -675,7 +676,7 @@ export class SigstoreVerifier {
675
676
  } else {
676
677
  // data is the file content, compute the digest
677
678
  artifactDigest = Uint8ArrayToHex(
678
- new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(data)))
679
+ new Uint8Array(await crypto.subtle.digest(HashAlgorithms.SHA256, data as Uint8Array<ArrayBuffer>))
679
680
  );
680
681
  }
681
682
 
@@ -13,11 +13,10 @@
13
13
  * - Adds verifyBundleTimestamp for Sigstore bundle integration (new functionality)
14
14
  */
15
15
 
16
+ import { base64ToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
17
+ import { CertificateChainVerifier, X509Certificate } from "../x509/index.js";
18
+ import { RawTimestampAuthority } from "../interfaces.js";
16
19
  import { RFC3161Timestamp } from "../rfc3161/index.js";
17
- import { X509Certificate, CertificateChainVerifier } from "../x509/index.js";
18
- import { bufferEqual } from "../crypto.js";
19
- import { base64ToUint8Array, Uint8ArrayToHex } from "../encoding.js";
20
- import type { RawTimestampAuthority } from "../interfaces.js";
21
20
 
22
21
  /**
23
22
  * Verifies an RFC3161 timestamp against a set of timestamp authorities
@@ -110,8 +109,8 @@ function filterCAsBySerialAndIssuer(
110
109
  base64ToUint8Array(ca.certChain.certificates[0].rawBytes)
111
110
  );
112
111
 
113
- return bufferEqual(leafCert.serialNumber, criteria.serialNumber) &&
114
- bufferEqual(leafCert.issuer, criteria.issuer);
112
+ return uint8ArrayEqual(leafCert.serialNumber, criteria.serialNumber) &&
113
+ uint8ArrayEqual(leafCert.issuer, criteria.issuer);
115
114
  });
116
115
  }
117
116
 
package/src/tlog/body.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * - Direct bundle comparison instead of SignatureContent abstraction
10
10
  */
11
11
 
12
- import { base64Decode } from "../encoding.js";
12
+ import { base64Decode } from "@freedomofpress/crypto-browser";
13
13
  import type { SigstoreBundle, TLogEntry } from "../bundle.js";
14
14
  import { verifyHashedRekordBody } from "./hashedrekord.js";
15
15
  import { verifyDSSEBody } from "./dsse.js";
@@ -19,8 +19,14 @@ Follows the signed note format specification:
19
19
  https://github.com/transparency-dev/formats/blob/main/log/README.md
20
20
  */
21
21
 
22
- import { base64ToUint8Array, stringToUint8Array, toArrayBuffer, uint8ArrayEqual, Uint8ArrayToHex } from "../encoding.js";
23
- import { importKey, verifySignature } from "../crypto.js";
22
+ import {
23
+ base64ToUint8Array,
24
+ importKey,
25
+ KeyTypes,
26
+ stringToUint8Array,
27
+ uint8ArrayEqual,
28
+ verifySignature,
29
+ } from "@freedomofpress/crypto-browser";
24
30
  import type { TLogEntry } from "../bundle.js";
25
31
  import type { RawLogs } from "../interfaces.js";
26
32
 
@@ -223,17 +229,17 @@ async function importTLogKey(tlog: RawLogs[0]): Promise<CryptoKey> {
223
229
 
224
230
  if (keyDetails === "ecdsa-sha2-nistp256") {
225
231
  // SSH-style ECDSA P-256 format used in tests
226
- keyType = "ecdsa";
232
+ keyType = KeyTypes.Ecdsa;
227
233
  scheme = "P256-SHA256";
228
234
  } else if (keyDetails.includes("ECDSA")) {
229
- keyType = "ecdsa";
235
+ keyType = KeyTypes.Ecdsa;
230
236
  // Extract the curve and hash, e.g., "P256_SHA_256" from "PKIX_ECDSA_P256_SHA_256"
231
237
  scheme = keyDetails.replace("PKIX_ECDSA_", "").replaceAll("_", "-");
232
238
  } else if (keyDetails.includes("ED25519")) {
233
- keyType = "ed25519";
234
- scheme = "ed25519";
239
+ keyType = KeyTypes.Ed25519;
240
+ scheme = KeyTypes.Ed25519;
235
241
  } else if (keyDetails.includes("RSA")) {
236
- keyType = "rsa";
242
+ keyType = KeyTypes.RSA;
237
243
  // Extract RSA details, e.g., "PSS_SHA_256" from "PKIX_RSA_PSS_SHA_256"
238
244
  scheme = keyDetails.replace("PKIX_RSA_", "").replaceAll("_", "-");
239
245
  } else {
package/src/tlog/dsse.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * - Adds verifyDSSE002Body() - new functionality (reference only supports v0.0.1)
12
12
  */
13
13
 
14
- import { base64ToUint8Array, hexToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
14
+ import { base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
15
15
  import { HashAlgorithms } from "../interfaces.js";
16
16
  import type { SigstoreBundle } from "../bundle.js";
17
17
  import type { RekorEntry } from "./body.js";
@@ -90,7 +90,7 @@ async function verifyDSSE001Body(
90
90
 
91
91
  const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
92
92
  const bundleHashBytes = new Uint8Array(
93
- await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes))
93
+ await crypto.subtle.digest(HashAlgorithms.SHA256, payloadBytes as Uint8Array<ArrayBuffer>)
94
94
  );
95
95
 
96
96
  if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
@@ -138,7 +138,7 @@ async function verifyDSSE002Body(
138
138
 
139
139
  const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
140
140
  const bundleHashBytes = new Uint8Array(
141
- await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes))
141
+ await crypto.subtle.digest(HashAlgorithms.SHA256, payloadBytes as Uint8Array<ArrayBuffer>)
142
142
  );
143
143
 
144
144
  if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
@@ -10,7 +10,7 @@
10
10
  * - Adds verifyHashedRekordV002Body() - new functionality (reference only supports v0.0.1)
11
11
  */
12
12
 
13
- import { base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "../encoding.js";
13
+ import { base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
14
14
  import type { SigstoreBundle } from "../bundle.js";
15
15
  import type { RekorEntry } from "./body.js";
16
16
 
@@ -10,7 +10,7 @@
10
10
  * - Uses crypto.subtle.digest for hash computation instead of Node.js crypto
11
11
  */
12
12
 
13
- import { base64Decode, base64ToUint8Array, hexToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
13
+ import { base64Decode, base64ToUint8Array, hexToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
14
14
  import { HashAlgorithms } from "../interfaces.js";
15
15
  import type { SigstoreBundle } from "../bundle.js";
16
16
  import type { RekorEntry } from "./body.js";
@@ -92,7 +92,7 @@ export async function verifyIntotoBody(
92
92
 
93
93
  const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
94
94
  const bundleHashBytes = new Uint8Array(
95
- await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(payloadBytes))
95
+ await crypto.subtle.digest(HashAlgorithms.SHA256, payloadBytes as Uint8Array<ArrayBuffer>)
96
96
  );
97
97
 
98
98
  if (!uint8ArrayEqual(tlogHashBytes, bundleHashBytes)) {
@@ -6,9 +6,9 @@ Key differences:
6
6
  - Uses Uint8Array instead of Buffer
7
7
  - Uses async Web Crypto API (crypto.subtle.digest) instead of sync Node.js crypto
8
8
  - Base64 decoding via custom base64ToUint8Array instead of Buffer.from
9
- - Custom uint8ArrayEqual instead of crypto.bufferEqual
9
+ - uint8ArrayEqual from crypto-browser instead of Node.js crypto.timingSafeEqual
10
10
  */
11
- import { base64ToUint8Array, toArrayBuffer, uint8ArrayEqual } from "../encoding.js";
11
+ import { base64ToUint8Array, uint8ArrayEqual } from "@freedomofpress/crypto-browser";
12
12
  import { HashAlgorithms } from "../interfaces.js";
13
13
  import type { TLogEntry } from "../bundle.js";
14
14
 
@@ -138,7 +138,7 @@ async function hashChildren(
138
138
  data.set(left, RFC6962_NODE_HASH_PREFIX.length);
139
139
  data.set(right, RFC6962_NODE_HASH_PREFIX.length + left.length);
140
140
 
141
- const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(data));
141
+ const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, data as Uint8Array<ArrayBuffer>);
142
142
  return new Uint8Array(hash);
143
143
  }
144
144
 
@@ -147,6 +147,6 @@ async function hashLeaf(leaf: Uint8Array): Promise<Uint8Array> {
147
147
  data.set(RFC6962_LEAF_HASH_PREFIX, 0);
148
148
  data.set(leaf, RFC6962_LEAF_HASH_PREFIX.length);
149
149
 
150
- const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, toArrayBuffer(data));
150
+ const hash = await crypto.subtle.digest(HashAlgorithms.SHA256, data as Uint8Array<ArrayBuffer>);
151
151
  return new Uint8Array(hash);
152
152
  }
package/src/trust/tuf.ts CHANGED
@@ -7,9 +7,9 @@
7
7
  * Reference: https://github.com/freedomofpress/tuf-browser
8
8
  */
9
9
 
10
- import type { TrustedRoot } from "../interfaces.js";
11
- import { Uint8ArrayToString } from "../encoding.js";
12
- import type { TUFClient } from "tuf-browser/dist/tuf.js";
10
+ import { Uint8ArrayToString } from "@freedomofpress/crypto-browser";
11
+ import type { TUFClient } from "@freedomofpress/tuf-browser";
12
+ import { TrustedRoot } from "../interfaces.js";
13
13
 
14
14
  /**
15
15
  * Options for TrustedRootProvider configuration
@@ -106,7 +106,7 @@ export class TrustedRootProvider {
106
106
  }
107
107
 
108
108
  try {
109
- const { TUFClient } = await import('tuf-browser/dist/tuf.js');
109
+ const { TUFClient } = await import('@freedomofpress/tuf-browser');
110
110
 
111
111
  // Get initial root metadata
112
112
  const rootMetadata = this.initialRoot || await this.getDefaultRoot();
@@ -179,10 +179,10 @@ export class TrustedRootProvider {
179
179
 
180
180
  // Fetch the trusted root target via TUF
181
181
  // TUF will handle all verification (signatures, rollback protection, etc.)
182
- const trustedRootBytes = await this.tufClient.getTarget(this.trustedRootTarget);
182
+ const trustedRootBuffer = await this.tufClient.getTarget(this.trustedRootTarget);
183
183
 
184
184
  // Parse the trusted root JSON
185
- const trustedRootJson = Uint8ArrayToString(trustedRootBytes);
185
+ const trustedRootJson = Uint8ArrayToString(new Uint8Array(trustedRootBuffer));
186
186
  const trustedRoot = JSON.parse(trustedRootJson) as TrustedRoot;
187
187
 
188
188
  // Cache the result
package/src/x509/cert.ts CHANGED
@@ -13,12 +13,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
- import { ASN1Obj } from "../asn1/index.js";
17
- import { bufferEqual, importKey, verifySignature } from "../crypto.js";
18
- import { Uint8ArrayToBase64 } from "../encoding.js";
16
+ import {
17
+ ASN1Obj,
18
+ importKey,
19
+ toDER,
20
+ Uint8ArrayToBase64,
21
+ uint8ArrayEqual,
22
+ verifySignature,
23
+ } from "@freedomofpress/crypto-browser";
19
24
  import { KeyTypes } from "../interfaces.js";
20
25
  import { ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS } from "../oid.js";
21
- import * as pem from "../pem.js";
22
26
  import {
23
27
  X509AuthorityKeyIDExtension,
24
28
  X509BasicConstraintsExtension,
@@ -50,7 +54,7 @@ export class X509Certificate {
50
54
  }
51
55
 
52
56
  public static parse(cert: Uint8Array | string): X509Certificate {
53
- const der = typeof cert === "string" ? pem.toDER(cert) : cert;
57
+ const der = typeof cert === "string" ? toDER(cert) : cert;
54
58
  const asn1 = ASN1Obj.parseBuffer(der);
55
59
  return new X509Certificate(asn1);
56
60
  }
@@ -112,7 +116,7 @@ export class X509Certificate {
112
116
  } else {
113
117
  scheme = "SHA256";
114
118
  }
115
- return importKey("RSA", `RSA_PKCS1V5_${scheme}`, Uint8ArrayToBase64(publicKey));
119
+ return importKey(KeyTypes.RSA, `RSA_PKCS1V5_${scheme}`, Uint8ArrayToBase64(publicKey));
116
120
  } else {
117
121
  // ECDSA key - the curve OID is in the second element
118
122
  const curveOID = spki.subs[0].subs[1]?.toOID();
@@ -233,7 +237,7 @@ export class X509Certificate {
233
237
  }
234
238
 
235
239
  public equals(other: X509Certificate): boolean {
236
- return bufferEqual(this.root.toDER(), other.root.toDER());
240
+ return uint8ArrayEqual(this.root.toDER(), other.root.toDER());
237
241
  }
238
242
 
239
243
  // Creates a copy of the certificate with a new buffer
package/src/x509/chain.ts CHANGED
@@ -23,11 +23,11 @@ limitations under the License.
23
23
  * Key differences from sigstore-js:
24
24
  * - Browser-compatible: async verify() method for Web Crypto API
25
25
  * - Uses Uint8Array instead of Buffer for binary data
26
- * - Uses bufferEqual for Uint8Array comparisons
26
+ * - Uses uint8ArrayEqual for Uint8Array comparisons
27
27
  */
28
28
 
29
+ import { uint8ArrayEqual } from "@freedomofpress/crypto-browser";
29
30
  import { X509Certificate } from "./cert.js";
30
- import { bufferEqual } from "../crypto.js";
31
31
 
32
32
  interface CertificateChainVerifierOptions {
33
33
  trustedCerts: X509Certificate[];
@@ -123,7 +123,7 @@ export class CertificateChainVerifier {
123
123
  let issuers: X509Certificate[] = [];
124
124
  let keyIdentifier: Uint8Array | undefined;
125
125
 
126
- if (bufferEqual(certificate.subject, certificate.issuer)) {
126
+ if (uint8ArrayEqual(certificate.subject, certificate.issuer)) {
127
127
  if (await certificate.verify()) {
128
128
  return [certificate];
129
129
  }
@@ -137,7 +137,7 @@ export class CertificateChainVerifier {
137
137
  if (keyIdentifier) {
138
138
  if (possibleIssuer.extSubjectKeyID) {
139
139
  if (
140
- bufferEqual(
140
+ uint8ArrayEqual(
141
141
  possibleIssuer.extSubjectKeyID.keyIdentifier,
142
142
  keyIdentifier
143
143
  )
@@ -148,7 +148,7 @@ export class CertificateChainVerifier {
148
148
  }
149
149
  }
150
150
 
151
- if (bufferEqual(possibleIssuer.subject, certificate.issuer)) {
151
+ if (uint8ArrayEqual(possibleIssuer.subject, certificate.issuer)) {
152
152
  issuers.push(possibleIssuer);
153
153
  }
154
154
  });
@@ -180,7 +180,7 @@ export class CertificateChainVerifier {
180
180
  }
181
181
 
182
182
  for (let i = path.length - 2; i >= 0; i--) {
183
- if (!bufferEqual(path[i].issuer, path[i + 1].subject)) {
183
+ if (!uint8ArrayEqual(path[i].issuer, path[i + 1].subject)) {
184
184
  throw new Error("incorrect certificate name chaining");
185
185
  }
186
186
  }
package/src/x509/ext.ts CHANGED
@@ -13,9 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
- import { ASN1Obj } from "../asn1/index.js";
17
- import { toArrayBuffer, Uint8ArrayToString } from "../encoding.js";
18
- import { ByteStream } from "../stream.js";
16
+ import { ASN1Obj, ByteStream, Uint8ArrayToString } from "@freedomofpress/crypto-browser";
19
17
  import { SignedCertificateTimestamp } from "./sct.js";
20
18
 
21
19
  // https://www.rfc-editor.org/rfc/rfc5280#section-4.1
@@ -187,7 +185,7 @@ export class X509SCTExtension extends X509Extension {
187
185
 
188
186
  get signedCertificateTimestamps(): SignedCertificateTimestamp[] {
189
187
  const buf = this.extnValueObj.subs[0].value;
190
- const stream = new ByteStream(toArrayBuffer(buf));
188
+ const stream = new ByteStream(buf);
191
189
 
192
190
  // The overall list length is encoded in the first two bytes -- note this
193
191
  // is the length of the list in bytes, NOT the number of SCTs in the list
package/src/x509/sct.ts CHANGED
@@ -13,9 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
- import { verifySignature } from "../crypto.js";
17
- import { readBigInt64BE, toArrayBuffer } from "../encoding.js";
18
- import { ByteStream } from "../stream.js";
16
+ import { ByteStream, readBigInt64BE, verifySignature } from "@freedomofpress/crypto-browser";
19
17
 
20
18
  interface SCTOptions {
21
19
  version: number;
@@ -111,7 +109,7 @@ export class SignedCertificateTimestamp {
111
109
  // https://www.rfc-editor.org/rfc/rfc6962#section-3.2
112
110
  // https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.4.1
113
111
  public static parse(buf: Uint8Array): SignedCertificateTimestamp {
114
- const stream = new ByteStream(toArrayBuffer(buf));
112
+ const stream = new ByteStream(buf);
115
113
 
116
114
  // Version - enum { v1(0), (255) }
117
115
  const version = stream.getUint8();
@@ -2,25 +2,13 @@
2
2
  import { defineConfig } from "vite";
3
3
 
4
4
  export default defineConfig({
5
- build: {
6
- minify: false,
7
- outDir: "dist",
8
- target: "esnext",
9
- lib: {
10
- entry: "src/index.ts",
11
- formats: ["es"],
12
- fileName: "index",
13
- },
14
- },
15
5
  test: {
16
- globals: true,
6
+ include: ["**/*.browser.test.ts"],
17
7
  browser: {
18
- provider: "playwright",
19
8
  enabled: true,
20
- headless: false,
21
- instances: [
22
- { browser: "chromium" },
23
- ],
9
+ provider: "playwright",
10
+ headless: true,
11
+ instances: [{ browser: "chromium" }],
24
12
  },
25
13
  },
26
14
  });
@@ -1,5 +0,0 @@
1
- export declare class ASN1ParseError extends Error {
2
- }
3
- export declare class ASN1TypeError extends Error {
4
- }
5
- //# sourceMappingURL=error.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/asn1/error.ts"],"names":[],"mappings":"AAeA,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAE5C,qBAAa,aAAc,SAAQ,KAAK;CAAG"}
@@ -1,20 +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 class ASN1ParseError extends Error {
17
- }
18
- export class ASN1TypeError extends Error {
19
- }
20
- //# sourceMappingURL=error.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/asn1/error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,MAAM,OAAO,aAAc,SAAQ,KAAK;CAAG"}
@@ -1,2 +0,0 @@
1
- export { ASN1Obj } from "./obj.js";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/asn1/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -1,17 +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";
17
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/asn1/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -1,4 +0,0 @@
1
- import { ByteStream } from "../stream.js";
2
- export declare function decodeLength(stream: ByteStream): number;
3
- export declare function encodeLength(len: number): Uint8Array;
4
- //# sourceMappingURL=length.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"length.d.ts","sourceRoot":"","sources":["../../src/asn1/length.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA8BvD;AAGD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAgBpD"}
@@ -1,59 +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
- // Decodes the length of a DER-encoded ANS.1 element from the supplied stream.
18
- // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-encoded-length-and-value-bytes
19
- export function decodeLength(stream) {
20
- const buf = stream.getUint8();
21
- // If the most significant bit is UNSET the length is just the value of the
22
- // byte.
23
- if ((buf & 0x80) === 0x00) {
24
- return buf;
25
- }
26
- // Otherwise, the lower 7 bits of the first byte indicate the number of bytes
27
- // that follow to encode the length.
28
- const byteCount = buf & 0x7f;
29
- // Ensure the encoded length can safely fit in a JS number.
30
- if (byteCount > 6) {
31
- throw new ASN1ParseError("length exceeds 6 byte limit");
32
- }
33
- // Iterate over the bytes that encode the length.
34
- let len = 0;
35
- for (let i = 0; i < byteCount; i++) {
36
- len = len * 256 + stream.getUint8();
37
- }
38
- // This is a valid ASN.1 length encoding, but we don't support it.
39
- if (len === 0) {
40
- throw new ASN1ParseError("indefinite length encoding not supported");
41
- }
42
- return len;
43
- }
44
- // Translates the supplied value to a DER-encoded length.
45
- export function encodeLength(len) {
46
- if (len < 128) {
47
- return new Uint8Array([len]);
48
- }
49
- // Bitwise operations on large numbers are not supported in JS, so we need to
50
- // use BigInts.
51
- let val = BigInt(len);
52
- const bytes = [];
53
- while (val > 0n) {
54
- bytes.unshift(Number(val & 255n));
55
- val = val >> 8n;
56
- }
57
- return new Uint8Array([0x80 | bytes.length, ...bytes]);
58
- }
59
- //# sourceMappingURL=length.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"length.js","sourceRoot":"","sources":["../../src/asn1/length.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AAGF,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,8EAA8E;AAC9E,qGAAqG;AACrG,MAAM,UAAU,YAAY,CAAC,MAAkB;IAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAE9B,2EAA2E;IAC3E,QAAQ;IACR,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,oCAAoC;IACpC,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC;IAE7B,2DAA2D;IAC3D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,cAAc,CAAC,6BAA6B,CAAC,CAAC;IAC1D,CAAC;IAED,iDAAiD;IACjD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,CAAC;IAED,kEAAkE;IAClE,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,cAAc,CAAC,0CAA0C,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;QACd,OAAO,IAAI,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,6EAA6E;IAC7E,eAAe;IACf,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,EAAE,CAAC;IAEjB,OAAO,GAAG,GAAG,EAAE,EAAE,CAAC;QAChB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;QAClC,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC"}