@freedomofpress/sigstore-browser 0.1.1 → 0.1.3
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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/oid.d.ts +2 -0
- package/dist/oid.d.ts.map +1 -1
- package/dist/oid.js +5 -1
- package/dist/oid.js.map +1 -1
- package/dist/x509/cert.d.ts +11 -3
- package/dist/x509/cert.d.ts.map +1 -1
- package/dist/x509/cert.js +58 -26
- package/dist/x509/cert.js.map +1 -1
- package/package.json +5 -2
- package/src/index.browser.test.ts +37 -0
- package/src/index.ts +3 -0
- package/src/oid.ts +7 -1
- package/src/x509/cert.ts +68 -24
- package/vite.config.playwright.ts +4 -16
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,7 @@ export type { TrustedRoot, Sigstore, RawTimestampAuthority } from "./interfaces.
|
|
|
5
5
|
export { VerificationError, TimestampError, CertificateError, TLogError, SignatureError, PolicyError, } from "./errors.js";
|
|
6
6
|
export { verifyRFC3161Timestamp, verifyBundleTimestamp } from "./timestamp/tsa.js";
|
|
7
7
|
export { TrustedRootProvider, type TrustedRootProviderOptions } from "./trust/tuf.js";
|
|
8
|
+
export { X509Certificate, EXTENSION_OID_SCT } from "./x509/cert.js";
|
|
9
|
+
export { X509Extension } from "./x509/ext.js";
|
|
10
|
+
export { CertificateChainVerifier } from "./x509/chain.js";
|
|
8
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClJ,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClJ,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,7 @@ export { SigstoreVerifier } from "./sigstore.js";
|
|
|
2
2
|
export { VerificationError, TimestampError, CertificateError, TLogError, SignatureError, PolicyError, } from "./errors.js";
|
|
3
3
|
export { verifyRFC3161Timestamp, verifyBundleTimestamp } from "./timestamp/tsa.js";
|
|
4
4
|
export { TrustedRootProvider } from "./trust/tuf.js";
|
|
5
|
+
export { X509Certificate, EXTENSION_OID_SCT } from "./x509/cert.js";
|
|
6
|
+
export { X509Extension } from "./x509/ext.js";
|
|
7
|
+
export { CertificateChainVerifier } from "./x509/chain.js";
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAmC,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAmC,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/oid.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const ECDSA_SIGNATURE_ALGOS: Record<string, string>;
|
|
2
2
|
export declare const RSA_SIGNATURE_ALGOS: Record<string, string>;
|
|
3
|
+
export declare const OID_RSASSA_PSS = "1.2.840.113549.1.1.10";
|
|
3
4
|
export declare const SHA2_HASH_ALGOS: Record<string, string>;
|
|
5
|
+
export declare const DEFAULT_HASH_ALGORITHM = "sha256";
|
|
4
6
|
export declare const ECDSA_CURVE_NAMES: Record<string, string>;
|
|
5
7
|
//# sourceMappingURL=oid.d.ts.map
|
package/dist/oid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oid.d.ts","sourceRoot":"","sources":["../src/oid.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKxD,CAAC;AAGF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKtD,CAAC;
|
|
1
|
+
{"version":3,"file":"oid.d.ts","sourceRoot":"","sources":["../src/oid.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKxD,CAAC;AAGF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKtD,CAAC;AAGF,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIlD,CAAC;AAGF,eAAO,MAAM,sBAAsB,WAAW,CAAC;AAE/C,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIpD,CAAC"}
|
package/dist/oid.js
CHANGED
|
@@ -5,18 +5,22 @@ export const ECDSA_SIGNATURE_ALGOS = {
|
|
|
5
5
|
"1.2.840.10045.4.3.3": "sha384",
|
|
6
6
|
"1.2.840.10045.4.3.4": "sha512",
|
|
7
7
|
};
|
|
8
|
-
// RSA signature algorithms
|
|
8
|
+
// RSA signature algorithms (PKCS#1 v1.5)
|
|
9
9
|
export const RSA_SIGNATURE_ALGOS = {
|
|
10
10
|
"1.2.840.113549.1.1.11": "sha256", // sha256WithRSAEncryption
|
|
11
11
|
"1.2.840.113549.1.1.12": "sha384", // sha384WithRSAEncryption
|
|
12
12
|
"1.2.840.113549.1.1.13": "sha512", // sha512WithRSAEncryption
|
|
13
13
|
"1.2.840.113549.1.1.5": "sha1", // sha1WithRSAEncryption
|
|
14
14
|
};
|
|
15
|
+
// RSASSA-PSS OID - hash algorithm must be parsed from signature algorithm parameters
|
|
16
|
+
export const OID_RSASSA_PSS = "1.2.840.113549.1.1.10";
|
|
15
17
|
export const SHA2_HASH_ALGOS = {
|
|
16
18
|
"2.16.840.1.101.3.4.2.1": "sha256",
|
|
17
19
|
"2.16.840.1.101.3.4.2.2": "sha384",
|
|
18
20
|
"2.16.840.1.101.3.4.2.3": "sha512",
|
|
19
21
|
};
|
|
22
|
+
// Default hash algorithm used when not specified
|
|
23
|
+
export const DEFAULT_HASH_ALGORITHM = "sha256";
|
|
20
24
|
export const ECDSA_CURVE_NAMES = {
|
|
21
25
|
"1.2.840.10045.3.1.7": "secp256r1",
|
|
22
26
|
"1.3.132.0.34": "secp384r1",
|
package/dist/oid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oid.js","sourceRoot":"","sources":["../src/oid.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;CAChC,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"oid.js","sourceRoot":"","sources":["../src/oid.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;IAC/B,qBAAqB,EAAE,QAAQ;CAChC,CAAC;AAEF,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,uBAAuB,EAAE,QAAQ,EAAE,0BAA0B;IAC7D,uBAAuB,EAAE,QAAQ,EAAE,0BAA0B;IAC7D,uBAAuB,EAAE,QAAQ,EAAE,0BAA0B;IAC7D,sBAAsB,EAAE,MAAM,EAAK,wBAAwB;CAC5D,CAAC;AAEF,qFAAqF;AACrF,MAAM,CAAC,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAEtD,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,wBAAwB,EAAE,QAAQ;IAClC,wBAAwB,EAAE,QAAQ;IAClC,wBAAwB,EAAE,QAAQ;CACnC,CAAC;AAEF,iDAAiD;AACjD,MAAM,CAAC,MAAM,sBAAsB,GAAG,QAAQ,CAAC;AAE/C,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,qBAAqB,EAAE,WAAW;IAClC,cAAc,EAAE,WAAW;IAC3B,cAAc,EAAE,WAAW;CAC5B,CAAC"}
|
package/dist/x509/cert.d.ts
CHANGED
|
@@ -14,12 +14,20 @@ export declare class X509Certificate {
|
|
|
14
14
|
get subject(): Uint8Array;
|
|
15
15
|
get publicKey(): Uint8Array;
|
|
16
16
|
/**
|
|
17
|
-
* Import the public key with a specific hash algorithm for RSA keys
|
|
18
|
-
* For ECDSA keys,
|
|
17
|
+
* Import the public key with a specific hash algorithm and signature scheme for RSA keys.
|
|
18
|
+
* For ECDSA keys, both parameters are ignored.
|
|
19
|
+
* @param hashAlg - Hash algorithm (e.g., "sha384") for RSA keys
|
|
20
|
+
* @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5
|
|
19
21
|
*/
|
|
20
|
-
getPublicKeyObj(hashAlg?: string): Promise<CryptoKey>;
|
|
22
|
+
getPublicKeyObj(hashAlg?: string, usePss?: boolean): Promise<CryptoKey>;
|
|
21
23
|
get publicKeyObj(): Promise<CryptoKey>;
|
|
22
24
|
get signatureAlgorithm(): string;
|
|
25
|
+
get signatureAlgorithmOid(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Parse hash algorithm from RSA-PSS signature algorithm parameters.
|
|
28
|
+
* RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }
|
|
29
|
+
*/
|
|
30
|
+
private parseRsaPssHashAlgorithm;
|
|
23
31
|
get signatureValue(): Uint8Array;
|
|
24
32
|
get subjectAltName(): string | undefined;
|
|
25
33
|
get extensions(): ASN1Obj[];
|
package/dist/x509/cert.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cert.d.ts","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,OAAO,EAMR,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,mCAAmC,EACnC,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAWlB,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,qBAAa,eAAe;IACnB,IAAI,EAAE,OAAO,CAAC;gBAET,IAAI,EAAE,OAAO;WAIX,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,eAAe;IAM/D,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,OAAO,IAAI,MAAM,CAIpB;IAED,IAAI,YAAY,IAAI,UAAU,CAE7B;IAED,IAAI,SAAS,IAAI,IAAI,CAGpB;IAED,IAAI,QAAQ,IAAI,IAAI,CAGnB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,UAAU,CAExB;IAED,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED
|
|
1
|
+
{"version":3,"file":"cert.d.ts","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,OAAO,EAMR,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,mCAAmC,EACnC,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAWlB,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,qBAAa,eAAe;IACnB,IAAI,EAAE,OAAO,CAAC;gBAET,IAAI,EAAE,OAAO;WAIX,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,eAAe;IAM/D,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,OAAO,IAAI,MAAM,CAIpB;IAED,IAAI,YAAY,IAAI,UAAU,CAE7B;IAED,IAAI,SAAS,IAAI,IAAI,CAGpB;IAED,IAAI,QAAQ,IAAI,IAAI,CAGnB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,UAAU,CAExB;IAED,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED;;;;;OAKG;IACU,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAiCpF,IAAI,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC,CAErC;IAED,IAAI,kBAAkB,IAAI,MAAM,CAG/B;IAED,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAED;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IA0BhC,IAAI,cAAc,IAAI,UAAU,CAG/B;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,SAAS,CAGvC;IAED,IAAI,UAAU,IAAI,OAAO,EAAE,CAK1B;IAED,IAAI,WAAW,IAAI,qBAAqB,GAAG,SAAS,CAGnD;IAED,IAAI,mBAAmB,IAAI,6BAA6B,GAAG,SAAS,CAGnE;IAED,IAAI,iBAAiB,IAAI,mCAAmC,GAAG,SAAS,CAGvE;IAED,IAAI,iBAAiB,IAAI,2BAA2B,GAAG,SAAS,CAG/D;IAED,IAAI,eAAe,IAAI,yBAAyB,GAAG,SAAS,CAK3D;IAED,IAAI,MAAM,IAAI,gBAAgB,GAAG,SAAS,CAGzC;IAED,IAAI,iBAAiB,IAAI,kBAAkB,GAAG,SAAS,CAGtD;IAED,IAAI,iBAAiB,IAAI,kBAAkB,GAAG,SAAS,CAGtD;IAED,IAAI,IAAI,IAAI,OAAO,CASlB;IAEM,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAK3C,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAwBnE,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAIjC,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO;IAKvC,KAAK,IAAI,eAAe;IAM/B,OAAO,CAAC,aAAa;IAYrB,OAAO,KAAK,iBAAiB,GAG5B;IAGD,OAAO,KAAK,qBAAqB,GAGhC;IAGD,OAAO,KAAK,iBAAiB,GAG5B;IAGD,OAAO,KAAK,UAAU,GAGrB;IAGD,OAAO,KAAK,eAAe,GAG1B;IAGD,OAAO,KAAK,SAAS,GAGpB;IAGD,OAAO,KAAK,WAAW,GAGtB;IAGD,OAAO,KAAK,UAAU,GAGrB;IAGD,OAAO,KAAK,uBAAuB,GAGlC;IAKD,OAAO,KAAK,aAAa,GAIxB;CACF"}
|
package/dist/x509/cert.js
CHANGED
|
@@ -15,7 +15,7 @@ limitations under the License.
|
|
|
15
15
|
*/
|
|
16
16
|
import { ASN1Obj, importKey, toDER, Uint8ArrayToBase64, uint8ArrayEqual, verifySignature, } from "@freedomofpress/crypto-browser";
|
|
17
17
|
import { KeyTypes } from "../interfaces.js";
|
|
18
|
-
import { ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS } from "../oid.js";
|
|
18
|
+
import { DEFAULT_HASH_ALGORITHM, ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, OID_RSASSA_PSS, RSA_SIGNATURE_ALGOS, SHA2_HASH_ALGOS } from "../oid.js";
|
|
19
19
|
import { X509AuthorityKeyIDExtension, X509BasicConstraintsExtension, X509Extension, X509FulcioIssuerV1, X509FulcioIssuerV2, X509KeyUsageExtension, X509SCTExtension, X509SubjectAlternativeNameExtension, X509SubjectKeyIDExtension, } from "./ext.js";
|
|
20
20
|
// https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md
|
|
21
21
|
const EXTENSION_OID_SUBJECT_KEY_ID = "2.5.29.14";
|
|
@@ -65,28 +65,28 @@ export class X509Certificate {
|
|
|
65
65
|
return this.subjectPublicKeyInfoObj.toDER();
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Import the public key with a specific hash algorithm for RSA keys
|
|
69
|
-
* For ECDSA keys,
|
|
68
|
+
* Import the public key with a specific hash algorithm and signature scheme for RSA keys.
|
|
69
|
+
* For ECDSA keys, both parameters are ignored.
|
|
70
|
+
* @param hashAlg - Hash algorithm (e.g., "sha384") for RSA keys
|
|
71
|
+
* @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5
|
|
70
72
|
*/
|
|
71
|
-
async getPublicKeyObj(hashAlg) {
|
|
73
|
+
async getPublicKeyObj(hashAlg, usePss) {
|
|
72
74
|
const publicKey = this.subjectPublicKeyInfoObj.toDER();
|
|
73
75
|
const spki = ASN1Obj.parseBuffer(publicKey);
|
|
74
76
|
const algorithmOID = spki.subs[0].subs[0].toOID();
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
return importKey(KeyTypes.RSA, `RSA_PKCS1V5_${scheme}`, Uint8ArrayToBase64(publicKey));
|
|
77
|
+
// RSA key (OID 1.2.840.113549.1.1.1) or RSA-PSS key (OID 1.2.840.113549.1.1.10)
|
|
78
|
+
const isRsaKey = algorithmOID === "1.2.840.113549.1.1.1";
|
|
79
|
+
const isRsaPssKey = algorithmOID === OID_RSASSA_PSS;
|
|
80
|
+
if (isRsaPssKey) {
|
|
81
|
+
// WebCrypto doesn't support importing keys with id-RSASSA-PSS OID, only rsaEncryption
|
|
82
|
+
throw new Error("RSA-PSS public keys (id-RSASSA-PSS OID) are not supported by WebCrypto. " +
|
|
83
|
+
"Only certificates with standard RSA keys (rsaEncryption OID) signed using RSA-PSS are supported.");
|
|
84
|
+
}
|
|
85
|
+
if (isRsaKey) {
|
|
86
|
+
const hash = hashAlg || DEFAULT_HASH_ALGORITHM;
|
|
87
|
+
// crypto-browser extracts hash from scheme and uses PSS unless "PKCS1" is present
|
|
88
|
+
const scheme = usePss ? hash : `PKCS1_${hash}`;
|
|
89
|
+
return importKey(KeyTypes.RSA, scheme, Uint8ArrayToBase64(publicKey));
|
|
90
90
|
}
|
|
91
91
|
else {
|
|
92
92
|
// ECDSA key - the curve OID is in the second element
|
|
@@ -103,7 +103,36 @@ export class X509Certificate {
|
|
|
103
103
|
}
|
|
104
104
|
get signatureAlgorithm() {
|
|
105
105
|
const oid = this.signatureAlgorithmObj.subs[0].toOID();
|
|
106
|
-
return ECDSA_SIGNATURE_ALGOS[oid];
|
|
106
|
+
return ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid] || this.parseRsaPssHashAlgorithm();
|
|
107
|
+
}
|
|
108
|
+
get signatureAlgorithmOid() {
|
|
109
|
+
return this.signatureAlgorithmObj.subs[0].toOID();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse hash algorithm from RSA-PSS signature algorithm parameters.
|
|
113
|
+
* RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }
|
|
114
|
+
*/
|
|
115
|
+
parseRsaPssHashAlgorithm() {
|
|
116
|
+
const sigAlgOid = this.signatureAlgorithmObj.subs[0].toOID();
|
|
117
|
+
if (sigAlgOid !== OID_RSASSA_PSS) {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
// RSA-PSS has parameters in the second element of the signature algorithm sequence
|
|
121
|
+
const params = this.signatureAlgorithmObj.subs[1];
|
|
122
|
+
if (!params || params.subs.length === 0) {
|
|
123
|
+
return DEFAULT_HASH_ALGORITHM;
|
|
124
|
+
}
|
|
125
|
+
// First element is hashAlgorithm [0] EXPLICIT
|
|
126
|
+
const hashAlgWrapper = params.subs[0];
|
|
127
|
+
if (hashAlgWrapper && hashAlgWrapper.subs.length > 0) {
|
|
128
|
+
// The wrapper contains a SEQUENCE with the hash algorithm OID
|
|
129
|
+
const hashAlgSeq = hashAlgWrapper.subs[0];
|
|
130
|
+
if (hashAlgSeq && hashAlgSeq.subs.length > 0) {
|
|
131
|
+
const hashOid = hashAlgSeq.subs[0].toOID();
|
|
132
|
+
return SHA2_HASH_ALGOS[hashOid] || DEFAULT_HASH_ALGORITHM;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return DEFAULT_HASH_ALGORITHM;
|
|
107
136
|
}
|
|
108
137
|
get signatureValue() {
|
|
109
138
|
// Signature value is a bit string, so we need to skip the first byte
|
|
@@ -167,14 +196,17 @@ export class X509Certificate {
|
|
|
167
196
|
}
|
|
168
197
|
async verify(issuerCertificate) {
|
|
169
198
|
// Extract the hash algorithm from this certificate's signature algorithm
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
199
|
+
const sigAlgOID = this.signatureAlgorithmOid;
|
|
200
|
+
const isRsaPss = sigAlgOID === OID_RSASSA_PSS;
|
|
201
|
+
// Get hash algorithm - for RSA-PSS, parse from parameters; otherwise lookup in tables
|
|
202
|
+
const hashAlg = isRsaPss
|
|
203
|
+
? this.parseRsaPssHashAlgorithm()
|
|
204
|
+
: (RSA_SIGNATURE_ALGOS[sigAlgOID] || ECDSA_SIGNATURE_ALGOS[sigAlgOID]);
|
|
173
205
|
// Use the issuer's public key if provided, otherwise use the subject's (for self-signed certs)
|
|
174
|
-
// Import with the correct hash algorithm for this certificate's signature
|
|
206
|
+
// Import with the correct hash algorithm and key type for this certificate's signature
|
|
175
207
|
const publicKeyObj = issuerCertificate
|
|
176
|
-
? await issuerCertificate.getPublicKeyObj(hashAlg)
|
|
177
|
-
: await this.getPublicKeyObj(hashAlg);
|
|
208
|
+
? await issuerCertificate.getPublicKeyObj(hashAlg, isRsaPss)
|
|
209
|
+
: await this.getPublicKeyObj(hashAlg, isRsaPss);
|
|
178
210
|
return await verifySignature(publicKeyObj, this.tbsCertificate.toDER(), this.signatureValue, this.signatureAlgorithm);
|
|
179
211
|
}
|
|
180
212
|
validForDate(date) {
|
package/dist/x509/cert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cert.js","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;EAcE;AACF,OAAO,EACL,OAAO,EACP,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cert.js","sourceRoot":"","sources":["../../src/x509/cert.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freedomofpress/sigstore-browser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A minimal browser-only Sigstore verification library.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc",
|
|
15
|
-
"test": "vitest run",
|
|
15
|
+
"test": "vitest run --config vite.config.playwright.ts",
|
|
16
|
+
"test:node": "vitest run",
|
|
16
17
|
"coverage": "vitest run --coverage",
|
|
17
18
|
"lint": "npx eslint . --fix && npx prettier --write ."
|
|
18
19
|
},
|
|
@@ -26,8 +27,10 @@
|
|
|
26
27
|
"license": "MIT",
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/node": "^24.0.14",
|
|
30
|
+
"@vitest/browser": "^3.2.4",
|
|
29
31
|
"@vitest/coverage-v8": "^3.2.4",
|
|
30
32
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
33
|
+
"playwright": "^1.57.0",
|
|
31
34
|
"typescript": "^5.8.3",
|
|
32
35
|
"typescript-eslint": "^8.37.0",
|
|
33
36
|
"vitest": "^3.2.4"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { SigstoreVerifier } from "./sigstore.js";
|
|
3
|
+
import { X509Certificate } from "./x509/cert.js";
|
|
3
4
|
|
|
4
5
|
describe("Sigstore Browser Integration Tests", () => {
|
|
5
6
|
it("should initialize SigstoreVerifier in browser", () => {
|
|
@@ -149,6 +150,42 @@ describe("Sigstore Browser Integration Tests", () => {
|
|
|
149
150
|
expect(valid).toBe(true);
|
|
150
151
|
});
|
|
151
152
|
|
|
153
|
+
it("should verify RSA-PSS signed X.509 certificate", async () => {
|
|
154
|
+
// Self-signed certificate with standard RSA key but RSA-PSS signature (SHA-256, salt=32)
|
|
155
|
+
// WebCrypto requires rsaEncryption OID for the public key, not id-RSASSA-PSS
|
|
156
|
+
const rsaPssCertPem = `-----BEGIN CERTIFICATE-----
|
|
157
|
+
MIIDhTCCAjmgAwIBAgIUYzfguLRx71Cbn2Ty7xCt3GH+N6AwQQYJKoZIhvcNAQEK
|
|
158
|
+
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
|
|
159
|
+
AKIDAgEgMB4xHDAaBgNVBAMME1Rlc3QgUlNBLVBTUyBTaWduZWQwHhcNMjUxMTMw
|
|
160
|
+
MDMwMDU2WhcNMjYxMTMwMDMwMDU2WjAeMRwwGgYDVQQDDBNUZXN0IFJTQS1QU1Mg
|
|
161
|
+
U2lnbmVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA29B/88QFBILg
|
|
162
|
+
YCWp1pF3xBj7FVhBUCv6JwyZAouYWUxgGmpFg6RLgbaWk59oDtEFQ5xRGSDXLuMW
|
|
163
|
+
GL5wZVCjSnmYcBsBDROO+HfLKwDRcHw09bJY979PDHPy5EPZale/JsdxE+fepUw1
|
|
164
|
+
XQDvlK5Dyp6WKl9UBjTtl6+LHKV/KTo+SiaQP2vsbZvTIt3s8MHybV/ixYXlSPQt
|
|
165
|
+
Kju50REAaqSSYqxNzsq8Z2sjJbFBcatt5C1JhfoSyIHz5D0slriv8835DYhk0u4n
|
|
166
|
+
bvNzXhWeF7htHTiPWCYwaTr5cgjyhEWg3SNP+Tu9dxCYVXm7/jWTHRdPqUPQqFsq
|
|
167
|
+
wXqsrzSP+wIDAQABo1MwUTAdBgNVHQ4EFgQU+UcBxKusOtY4lSjqyFuxQfN5zdIw
|
|
168
|
+
HwYDVR0jBBgwFoAU+UcBxKusOtY4lSjqyFuxQfN5zdIwDwYDVR0TAQH/BAUwAwEB
|
|
169
|
+
/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEI
|
|
170
|
+
MA0GCWCGSAFlAwQCAQUAogMCASADggEBAFIn3VpfydVvpI82NwfeGxWlhZhgD2dX
|
|
171
|
+
gJUhj6pcXqwnlCzpyRI4e3uNO1h9nr9UrogI0AV2IDhVdUYxz3F2/680JtxXpB1x
|
|
172
|
+
J02BSAYllvXgf9efc20lFzbPDzvMzKnwx3S3proewbJ4uVPHzvKubWsx8MwEuI0X
|
|
173
|
+
8xkI1qMIXgevTCt+LGhp+0C/u8WsW3or5ZI7GnZNowPJEAtZnfO+VORB7FvbzEGr
|
|
174
|
+
ewS+2T7Qz4oXaQMidPOjr1Q8WKqaKO4yCtC8cz4qVWi3lNqAcAGtonQMXUiflEWV
|
|
175
|
+
9kqKQx+LJYJqxKkBtDRnRLnVNn4+inotrgnV126LsCe3uLaGwJIFy1U=
|
|
176
|
+
-----END CERTIFICATE-----`;
|
|
177
|
+
|
|
178
|
+
const cert = X509Certificate.parse(rsaPssCertPem);
|
|
179
|
+
|
|
180
|
+
// Verify it's an RSA-PSS certificate
|
|
181
|
+
expect(cert.signatureAlgorithmOid).toBe("1.2.840.113549.1.1.10");
|
|
182
|
+
expect(cert.signatureAlgorithm).toBe("sha256");
|
|
183
|
+
|
|
184
|
+
// Verify the self-signed certificate (signature verification)
|
|
185
|
+
const valid = await cert.verify();
|
|
186
|
+
expect(valid).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
|
|
152
189
|
it("should support TextEncoder/TextDecoder for UTF-8", () => {
|
|
153
190
|
const encoder = new TextEncoder();
|
|
154
191
|
const decoder = new TextDecoder();
|
package/src/index.ts
CHANGED
|
@@ -12,3 +12,6 @@ export {
|
|
|
12
12
|
} from "./errors.js";
|
|
13
13
|
export { verifyRFC3161Timestamp, verifyBundleTimestamp } from "./timestamp/tsa.js";
|
|
14
14
|
export { TrustedRootProvider, type TrustedRootProviderOptions } from "./trust/tuf.js";
|
|
15
|
+
export { X509Certificate, EXTENSION_OID_SCT } from "./x509/cert.js";
|
|
16
|
+
export { X509Extension } from "./x509/ext.js";
|
|
17
|
+
export { CertificateChainVerifier } from "./x509/chain.js";
|
package/src/oid.ts
CHANGED
|
@@ -7,7 +7,7 @@ export const ECDSA_SIGNATURE_ALGOS: Record<string, string> = {
|
|
|
7
7
|
"1.2.840.10045.4.3.4": "sha512",
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
// RSA signature algorithms
|
|
10
|
+
// RSA signature algorithms (PKCS#1 v1.5)
|
|
11
11
|
export const RSA_SIGNATURE_ALGOS: Record<string, string> = {
|
|
12
12
|
"1.2.840.113549.1.1.11": "sha256", // sha256WithRSAEncryption
|
|
13
13
|
"1.2.840.113549.1.1.12": "sha384", // sha384WithRSAEncryption
|
|
@@ -15,12 +15,18 @@ export const RSA_SIGNATURE_ALGOS: Record<string, string> = {
|
|
|
15
15
|
"1.2.840.113549.1.1.5": "sha1", // sha1WithRSAEncryption
|
|
16
16
|
};
|
|
17
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
|
+
|
|
18
21
|
export const SHA2_HASH_ALGOS: Record<string, string> = {
|
|
19
22
|
"2.16.840.1.101.3.4.2.1": "sha256",
|
|
20
23
|
"2.16.840.1.101.3.4.2.2": "sha384",
|
|
21
24
|
"2.16.840.1.101.3.4.2.3": "sha512",
|
|
22
25
|
};
|
|
23
26
|
|
|
27
|
+
// Default hash algorithm used when not specified
|
|
28
|
+
export const DEFAULT_HASH_ALGORITHM = "sha256";
|
|
29
|
+
|
|
24
30
|
export const ECDSA_CURVE_NAMES: Record<string, string> = {
|
|
25
31
|
"1.2.840.10045.3.1.7": "secp256r1",
|
|
26
32
|
"1.3.132.0.34": "secp384r1",
|
package/src/x509/cert.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
verifySignature,
|
|
23
23
|
} from "@freedomofpress/crypto-browser";
|
|
24
24
|
import { KeyTypes } from "../interfaces.js";
|
|
25
|
-
import { ECDSA_CURVE_NAMES, ECDSA_SIGNATURE_ALGOS, RSA_SIGNATURE_ALGOS } from "../oid.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
26
|
import {
|
|
27
27
|
X509AuthorityKeyIDExtension,
|
|
28
28
|
X509BasicConstraintsExtension,
|
|
@@ -96,27 +96,33 @@ export class X509Certificate {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Import the public key with a specific hash algorithm for RSA keys
|
|
100
|
-
* For ECDSA keys,
|
|
99
|
+
* Import the public key with a specific hash algorithm and signature scheme for RSA keys.
|
|
100
|
+
* For ECDSA keys, both parameters are ignored.
|
|
101
|
+
* @param hashAlg - Hash algorithm (e.g., "sha384") for RSA keys
|
|
102
|
+
* @param usePss - If true, import as RSA-PSS key; if false, import as PKCS#1 v1.5
|
|
101
103
|
*/
|
|
102
|
-
public async getPublicKeyObj(hashAlg?: string): Promise<CryptoKey> {
|
|
104
|
+
public async getPublicKeyObj(hashAlg?: string, usePss?: boolean): Promise<CryptoKey> {
|
|
103
105
|
const publicKey = this.subjectPublicKeyInfoObj.toDER();
|
|
104
106
|
const spki = ASN1Obj.parseBuffer(publicKey);
|
|
105
107
|
const algorithmOID = spki.subs[0].subs[0].toOID();
|
|
106
108
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
// RSA key (OID 1.2.840.113549.1.1.1) or RSA-PSS key (OID 1.2.840.113549.1.1.10)
|
|
110
|
+
const isRsaKey = algorithmOID === "1.2.840.113549.1.1.1";
|
|
111
|
+
const isRsaPssKey = algorithmOID === OID_RSASSA_PSS;
|
|
112
|
+
|
|
113
|
+
if (isRsaPssKey) {
|
|
114
|
+
// WebCrypto doesn't support importing keys with id-RSASSA-PSS OID, only rsaEncryption
|
|
115
|
+
throw new Error(
|
|
116
|
+
"RSA-PSS public keys (id-RSASSA-PSS OID) are not supported by WebCrypto. " +
|
|
117
|
+
"Only certificates with standard RSA keys (rsaEncryption OID) signed using RSA-PSS are supported."
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (isRsaKey) {
|
|
122
|
+
const hash = hashAlg || DEFAULT_HASH_ALGORITHM;
|
|
123
|
+
// crypto-browser extracts hash from scheme and uses PSS unless "PKCS1" is present
|
|
124
|
+
const scheme = usePss ? hash : `PKCS1_${hash}`;
|
|
125
|
+
return importKey(KeyTypes.RSA, scheme, Uint8ArrayToBase64(publicKey));
|
|
120
126
|
} else {
|
|
121
127
|
// ECDSA key - the curve OID is in the second element
|
|
122
128
|
const curveOID = spki.subs[0].subs[1]?.toOID();
|
|
@@ -134,7 +140,41 @@ export class X509Certificate {
|
|
|
134
140
|
|
|
135
141
|
get signatureAlgorithm(): string {
|
|
136
142
|
const oid: string = this.signatureAlgorithmObj.subs[0].toOID();
|
|
137
|
-
return ECDSA_SIGNATURE_ALGOS[oid];
|
|
143
|
+
return ECDSA_SIGNATURE_ALGOS[oid] || RSA_SIGNATURE_ALGOS[oid] || this.parseRsaPssHashAlgorithm();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get signatureAlgorithmOid(): string {
|
|
147
|
+
return this.signatureAlgorithmObj.subs[0].toOID();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Parse hash algorithm from RSA-PSS signature algorithm parameters.
|
|
152
|
+
* RSA-PSS parameters are: SEQUENCE { hashAlgorithm, maskGenAlgorithm, saltLength, trailerField }
|
|
153
|
+
*/
|
|
154
|
+
private parseRsaPssHashAlgorithm(): string {
|
|
155
|
+
const sigAlgOid = this.signatureAlgorithmObj.subs[0].toOID();
|
|
156
|
+
if (sigAlgOid !== OID_RSASSA_PSS) {
|
|
157
|
+
return "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// RSA-PSS has parameters in the second element of the signature algorithm sequence
|
|
161
|
+
const params = this.signatureAlgorithmObj.subs[1];
|
|
162
|
+
if (!params || params.subs.length === 0) {
|
|
163
|
+
return DEFAULT_HASH_ALGORITHM;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// First element is hashAlgorithm [0] EXPLICIT
|
|
167
|
+
const hashAlgWrapper = params.subs[0];
|
|
168
|
+
if (hashAlgWrapper && hashAlgWrapper.subs.length > 0) {
|
|
169
|
+
// The wrapper contains a SEQUENCE with the hash algorithm OID
|
|
170
|
+
const hashAlgSeq = hashAlgWrapper.subs[0];
|
|
171
|
+
if (hashAlgSeq && hashAlgSeq.subs.length > 0) {
|
|
172
|
+
const hashOid = hashAlgSeq.subs[0].toOID();
|
|
173
|
+
return SHA2_HASH_ALGOS[hashOid] || DEFAULT_HASH_ALGORITHM;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return DEFAULT_HASH_ALGORITHM;
|
|
138
178
|
}
|
|
139
179
|
|
|
140
180
|
get signatureValue(): Uint8Array {
|
|
@@ -214,15 +254,19 @@ export class X509Certificate {
|
|
|
214
254
|
|
|
215
255
|
public async verify(issuerCertificate?: X509Certificate): Promise<boolean> {
|
|
216
256
|
// Extract the hash algorithm from this certificate's signature algorithm
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
257
|
+
const sigAlgOID = this.signatureAlgorithmOid;
|
|
258
|
+
const isRsaPss = sigAlgOID === OID_RSASSA_PSS;
|
|
259
|
+
|
|
260
|
+
// Get hash algorithm - for RSA-PSS, parse from parameters; otherwise lookup in tables
|
|
261
|
+
const hashAlg = isRsaPss
|
|
262
|
+
? this.parseRsaPssHashAlgorithm()
|
|
263
|
+
: (RSA_SIGNATURE_ALGOS[sigAlgOID] || ECDSA_SIGNATURE_ALGOS[sigAlgOID]);
|
|
220
264
|
|
|
221
265
|
// Use the issuer's public key if provided, otherwise use the subject's (for self-signed certs)
|
|
222
|
-
// Import with the correct hash algorithm for this certificate's signature
|
|
266
|
+
// Import with the correct hash algorithm and key type for this certificate's signature
|
|
223
267
|
const publicKeyObj = issuerCertificate
|
|
224
|
-
? await issuerCertificate.getPublicKeyObj(hashAlg)
|
|
225
|
-
: await this.getPublicKeyObj(hashAlg);
|
|
268
|
+
? await issuerCertificate.getPublicKeyObj(hashAlg, isRsaPss)
|
|
269
|
+
: await this.getPublicKeyObj(hashAlg, isRsaPss);
|
|
226
270
|
|
|
227
271
|
return await verifySignature(
|
|
228
272
|
publicKeyObj,
|
|
@@ -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
|
-
|
|
6
|
+
include: ["**/*.browser.test.ts"],
|
|
17
7
|
browser: {
|
|
18
|
-
provider: "playwright",
|
|
19
8
|
enabled: true,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
],
|
|
9
|
+
provider: "playwright",
|
|
10
|
+
headless: true,
|
|
11
|
+
instances: [{ browser: "chromium" }],
|
|
24
12
|
},
|
|
25
13
|
},
|
|
26
14
|
});
|