@sphereon/ssi-sdk-ext.x509-utils 0.24.1-unstable.93 → 0.25.0
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/x509/rsa-key.d.ts.map +1 -1
- package/dist/x509/x509-utils.d.ts +2 -2
- package/dist/x509/x509-utils.d.ts.map +1 -1
- package/dist/x509/x509-utils.js +10 -6
- package/dist/x509/x509-utils.js.map +1 -1
- package/dist/x509/x509-validator.d.ts +49 -5
- package/dist/x509/x509-validator.d.ts.map +1 -1
- package/dist/x509/x509-validator.js +186 -31
- package/dist/x509/x509-validator.js.map +1 -1
- package/package.json +3 -2
- package/src/x509/x509-utils.ts +4 -0
- package/src/x509/x509-validator.ts +248 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsa-key.d.ts","sourceRoot":"","sources":["../../src/x509/rsa-key.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,SAAS,CAAA;AAEjE,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG,YAAY,CAAA;AA2BpE,eAAO,MAAM,+BAA+B,eAAgB,MAAM;;;CAajE,CAAA;AAED,eAAO,MAAM,wBAAwB,QAC9B,UAAU,UACP,oBAAoB,GAAG,mBAAmB,kBAClC,aAAa,KAC5B,
|
|
1
|
+
{"version":3,"file":"rsa-key.d.ts","sourceRoot":"","sources":["../../src/x509/rsa-key.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,SAAS,CAAA;AAEjE,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG,YAAY,CAAA;AA2BpE,eAAO,MAAM,+BAA+B,eAAgB,MAAM;;;CAajE,CAAA;AAED,eAAO,MAAM,wBAAwB,QAC9B,UAAU,UACP,oBAAoB,GAAG,mBAAmB,kBAClC,aAAa,KAC5B,OAAO,CAAC,SAAS,CAKnB,CAAA;AAED,eAAO,MAAM,mBAAmB,WACtB,oBAAoB,GAAG,mBAAmB,kBAClC,aAAa,kBACb,MAAM,KACrB,OAAO,CAAC,MAAM,CAgBhB,CAAA"}
|
|
@@ -22,8 +22,8 @@ export declare function PEMToBinary(pem: string): Uint8Array;
|
|
|
22
22
|
* @param input The input in base64, with optional newlines
|
|
23
23
|
* @param inputEncoding
|
|
24
24
|
*/
|
|
25
|
-
export declare const base64ToHex: (input: string, inputEncoding?:
|
|
26
|
-
export declare const hexToBase64: (input: number | object | string, targetEncoding?:
|
|
25
|
+
export declare const base64ToHex: (input: string, inputEncoding?: "base64" | "base64pad" | "base64url" | "base64urlpad") => string;
|
|
26
|
+
export declare const hexToBase64: (input: number | object | string, targetEncoding?: "base64" | "base64pad" | "base64url" | "base64urlpad") => string;
|
|
27
27
|
export declare const hexToPEM: (hex: string, type: KeyVisibility) => string;
|
|
28
28
|
export declare function PEMToDer(pem: string): string;
|
|
29
29
|
export declare function derToPEM(cert: string, headerKey?: 'PUBLIC KEY' | 'RSA PRIVATE KEY' | 'PRIVATE KEY' | 'CERTIFICATE'): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x509-utils.d.ts","sourceRoot":"","sources":["../../src/x509/x509-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAInC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAuB3E;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAU1E;AAED,eAAO,MAAM,yBAAyB,SAAU,MAAM,GAAG,UAAU,KAAG,WASrE,CAAA;AAED,eAAO,MAAM,oBAAoB,UAAW,WAAW,SAAS,WAAW,KAAG,OAE7E,CAAA;AAED,eAAO,MAAM,WAAW,QAAS,MAAM,eAAc,aAAa;;;;;CAWjE,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,UAAU,eAAc,aAAa,KAAc,MAEhF,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,eAAc,aAAa,KAAc,UAE5E,CAAA;AACD,eAAO,MAAM,oBAAoB,QAAS,MAAM,WAE/C,CAAA;AAED,eAAO,MAAM,qBAAqB,QAAS,UAAU,eAAc,aAAa,KAAc,MAM7F,CAAA;AAED,eAAO,MAAM,mBAAmB,QAAS,MAAM,WAU9C,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,cAAc,MAAM,KAAG,MAc1D,CAAA;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAOnD;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,UAAW,MAAM,kBAAkB,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,WAG/G,CAAA;AAED,eAAO,MAAM,WAAW,UAAW,MAAM,GAAG,MAAM,GAAG,MAAM,mBAAmB,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,KAAG,MAMrI,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,QAAQ,aAAa,KAAG,MAa3D,CAAA;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,YAAY,GAAG,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"x509-utils.d.ts","sourceRoot":"","sources":["../../src/x509/x509-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAInC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAuB3E;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAU1E;AAED,eAAO,MAAM,yBAAyB,SAAU,MAAM,GAAG,UAAU,KAAG,WASrE,CAAA;AAED,eAAO,MAAM,oBAAoB,UAAW,WAAW,SAAS,WAAW,KAAG,OAE7E,CAAA;AAED,eAAO,MAAM,WAAW,QAAS,MAAM,eAAc,aAAa;;;;;CAWjE,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,UAAU,eAAc,aAAa,KAAc,MAEhF,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,eAAc,aAAa,KAAc,UAE5E,CAAA;AACD,eAAO,MAAM,oBAAoB,QAAS,MAAM,WAE/C,CAAA;AAED,eAAO,MAAM,qBAAqB,QAAS,UAAU,eAAc,aAAa,KAAc,MAM7F,CAAA;AAED,eAAO,MAAM,mBAAmB,QAAS,MAAM,WAU9C,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,cAAc,MAAM,KAAG,MAc1D,CAAA;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAOnD;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,UAAW,MAAM,kBAAkB,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,WAG/G,CAAA;AAED,eAAO,MAAM,WAAW,UAAW,MAAM,GAAG,MAAM,GAAG,MAAM,mBAAmB,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,KAAG,MAMrI,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,MAAM,QAAQ,aAAa,KAAG,MAa3D,CAAA;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,YAAY,GAAG,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,CAW3H"}
|
package/dist/x509/x509-utils.js
CHANGED
|
@@ -26,7 +26,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
29
|
+
exports.hexToPEM = exports.hexToBase64 = exports.base64ToHex = exports.PEMToHex = exports.publicKeyHexFromPEM = exports.hexKeyFromPEMBasedJwk = exports.privateKeyHexFromPEM = exports.PEMToJwk = exports.jwkToPEM = exports.toKeyObject = exports.areCertificatesEqual = exports.pemOrDerToX509Certificate = void 0;
|
|
30
|
+
exports.pemCertChainTox5c = pemCertChainTox5c;
|
|
31
|
+
exports.x5cToPemCertChain = x5cToPemCertChain;
|
|
32
|
+
exports.PEMToBinary = PEMToBinary;
|
|
33
|
+
exports.PEMToDer = PEMToDer;
|
|
34
|
+
exports.derToPEM = derToPEM;
|
|
30
35
|
const pkijs_1 = require("pkijs");
|
|
31
36
|
const u8a = __importStar(require("uint8arrays"));
|
|
32
37
|
// @ts-ignore
|
|
@@ -56,7 +61,6 @@ function pemCertChainTox5c(cert, maxDepth) {
|
|
|
56
61
|
}
|
|
57
62
|
return x5c;
|
|
58
63
|
}
|
|
59
|
-
exports.pemCertChainTox5c = pemCertChainTox5c;
|
|
60
64
|
function x5cToPemCertChain(x5c, maxDepth) {
|
|
61
65
|
if (!maxDepth) {
|
|
62
66
|
maxDepth = 0;
|
|
@@ -68,7 +72,6 @@ function x5cToPemCertChain(x5c, maxDepth) {
|
|
|
68
72
|
}
|
|
69
73
|
return pem;
|
|
70
74
|
}
|
|
71
|
-
exports.x5cToPemCertChain = x5cToPemCertChain;
|
|
72
75
|
const pemOrDerToX509Certificate = (cert) => {
|
|
73
76
|
if (typeof cert !== 'string') {
|
|
74
77
|
return pkijs_1.Certificate.fromBER(cert);
|
|
@@ -153,7 +156,6 @@ function PEMToBinary(pem) {
|
|
|
153
156
|
.replace(/\s/g, '');
|
|
154
157
|
return u8a.fromString(pemContents, 'base64pad');
|
|
155
158
|
}
|
|
156
|
-
exports.PEMToBinary = PEMToBinary;
|
|
157
159
|
/**
|
|
158
160
|
* Converts a base64 encoded string to hex string, removing any non-base64 characters, including newlines
|
|
159
161
|
* @param input The input in base64, with optional newlines
|
|
@@ -191,14 +193,16 @@ exports.hexToPEM = hexToPEM;
|
|
|
191
193
|
function PEMToDer(pem) {
|
|
192
194
|
return pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|[\n\r])/g, '');
|
|
193
195
|
}
|
|
194
|
-
exports.PEMToDer = PEMToDer;
|
|
195
196
|
function derToPEM(cert, headerKey) {
|
|
196
197
|
const key = headerKey !== null && headerKey !== void 0 ? headerKey : 'CERTIFICATE';
|
|
198
|
+
if (cert.includes(key)) {
|
|
199
|
+
// Was already in PEM it seems
|
|
200
|
+
return cert;
|
|
201
|
+
}
|
|
197
202
|
const matches = cert.match(/.{1,64}/g);
|
|
198
203
|
if (!matches) {
|
|
199
204
|
throw Error('Invalid cert input value supplied');
|
|
200
205
|
}
|
|
201
206
|
return `-----BEGIN ${key}-----\n${matches.join('\n')}\n-----END ${key}-----\n`;
|
|
202
207
|
}
|
|
203
|
-
exports.derToPEM = derToPEM;
|
|
204
208
|
//# sourceMappingURL=x509-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x509-utils.js","sourceRoot":"","sources":["../../src/x509/x509-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"x509-utils.js","sourceRoot":"","sources":["../../src/x509/x509-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ export type DNInfo = {
|
|
|
3
3
|
DN: string;
|
|
4
4
|
attributes: Record<string, string>;
|
|
5
5
|
};
|
|
6
|
-
export type
|
|
6
|
+
export type CertificateInfo = {
|
|
7
7
|
certificate?: any;
|
|
8
8
|
notBefore: Date;
|
|
9
9
|
notAfter: Date;
|
|
@@ -13,6 +13,7 @@ export type CertInfo = {
|
|
|
13
13
|
};
|
|
14
14
|
subject: {
|
|
15
15
|
dn: DNInfo;
|
|
16
|
+
subjectAlternativeNames: SubjectAlternativeName[];
|
|
16
17
|
};
|
|
17
18
|
};
|
|
18
19
|
export type X509ValidationResult = {
|
|
@@ -20,7 +21,23 @@ export type X509ValidationResult = {
|
|
|
20
21
|
critical: boolean;
|
|
21
22
|
message: string;
|
|
22
23
|
verificationTime: Date;
|
|
23
|
-
certificateChain?: Array<
|
|
24
|
+
certificateChain?: Array<CertificateInfo>;
|
|
25
|
+
client?: {
|
|
26
|
+
clientId: string;
|
|
27
|
+
clientIdScheme: ClientIdScheme;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare const getCertificateInfo: (certificate: Certificate, opts?: {
|
|
31
|
+
sanTypeFilter: SubjectAlternativeGeneralName | SubjectAlternativeGeneralName[];
|
|
32
|
+
}) => Promise<CertificateInfo>;
|
|
33
|
+
export type X509CertificateChainValidationOpts = {
|
|
34
|
+
trustRootWhenNoAnchors?: boolean;
|
|
35
|
+
allowSingleNoCAChainElement?: boolean;
|
|
36
|
+
blindlyTrustedAnchors?: string[];
|
|
37
|
+
client?: {
|
|
38
|
+
clientId: string;
|
|
39
|
+
clientIdScheme: ClientIdScheme;
|
|
40
|
+
};
|
|
24
41
|
};
|
|
25
42
|
/**
|
|
26
43
|
*
|
|
@@ -33,10 +50,37 @@ export declare const validateX509CertificateChain: ({ chain: pemOrDerChain, trus
|
|
|
33
50
|
chain: (Uint8Array | string)[];
|
|
34
51
|
trustAnchors?: string[];
|
|
35
52
|
verificationTime?: Date;
|
|
36
|
-
opts?:
|
|
37
|
-
trustRootWhenNoAnchors: boolean;
|
|
38
|
-
};
|
|
53
|
+
opts?: X509CertificateChainValidationOpts;
|
|
39
54
|
}) => Promise<X509ValidationResult>;
|
|
40
55
|
export declare const getIssuerDN: (cert: Certificate) => DNInfo;
|
|
41
56
|
export declare const getSubjectDN: (cert: Certificate) => DNInfo;
|
|
57
|
+
export declare const getCertificateSubjectPublicKeyJWK: (pemOrDerCert: string | Uint8Array | Certificate) => Promise<JsonWebKey>;
|
|
58
|
+
/**
|
|
59
|
+
* otherName [0] OtherName,
|
|
60
|
+
* rfc822Name [1] IA5String,
|
|
61
|
+
* dNSName [2] IA5String,
|
|
62
|
+
* x400Address [3] ORAddress,
|
|
63
|
+
* directoryName [4] Name,
|
|
64
|
+
* ediPartyName [5] EDIPartyName,
|
|
65
|
+
* uniformResourceIdentifier [6] IA5String,
|
|
66
|
+
* iPAddress [7] OCTET STRING,
|
|
67
|
+
* registeredID [8] OBJECT IDENTIFIER }
|
|
68
|
+
*/
|
|
69
|
+
export declare enum SubjectAlternativeGeneralName {
|
|
70
|
+
rfc822Name = 1,// email
|
|
71
|
+
dnsName = 2,
|
|
72
|
+
uniformResourceIdentifier = 6,
|
|
73
|
+
ipAddress = 7
|
|
74
|
+
}
|
|
75
|
+
export interface SubjectAlternativeName {
|
|
76
|
+
value: string;
|
|
77
|
+
type: SubjectAlternativeGeneralName;
|
|
78
|
+
}
|
|
79
|
+
export type ClientIdScheme = 'x509_san_dns' | 'x509_san_uri';
|
|
80
|
+
export declare const assertCertificateMatchesClientIdScheme: (certificate: Certificate, clientId: string, clientIdScheme: ClientIdScheme) => void;
|
|
81
|
+
export declare const validateCertificateChainMatchesClientIdScheme: (certificate: Certificate, clientId: string, clientIdScheme: ClientIdScheme) => Promise<X509ValidationResult>;
|
|
82
|
+
export declare const getSubjectAlternativeNames: (certificate: Certificate, opts?: {
|
|
83
|
+
typeFilter?: SubjectAlternativeGeneralName | SubjectAlternativeGeneralName[];
|
|
84
|
+
clientIdSchemeFilter?: ClientIdScheme;
|
|
85
|
+
}) => SubjectAlternativeName[];
|
|
42
86
|
//# sourceMappingURL=x509-validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x509-validator.d.ts","sourceRoot":"","sources":["../../src/x509/x509-validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"x509-validator.d.ts","sourceRoot":"","sources":["../../src/x509/x509-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -8,9 +31,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
31
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
32
|
});
|
|
10
33
|
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
11
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.getSubjectDN = exports.getIssuerDN = exports.validateX509CertificateChain = void 0;
|
|
38
|
+
exports.getSubjectAlternativeNames = exports.validateCertificateChainMatchesClientIdScheme = exports.assertCertificateMatchesClientIdScheme = exports.SubjectAlternativeGeneralName = exports.getCertificateSubjectPublicKeyJWK = exports.getSubjectDN = exports.getIssuerDN = exports.validateX509CertificateChain = exports.getCertificateInfo = void 0;
|
|
39
|
+
const js_x509_utils_1 = __importDefault(require("js-x509-utils"));
|
|
13
40
|
const pkijs_1 = require("pkijs");
|
|
41
|
+
const u8a = __importStar(require("uint8arrays"));
|
|
14
42
|
const x509_utils_1 = require("./x509-utils");
|
|
15
43
|
const defaultCryptoEngine = () => {
|
|
16
44
|
if (typeof self !== 'undefined') {
|
|
@@ -33,6 +61,21 @@ const defaultCryptoEngine = () => {
|
|
|
33
61
|
(0, pkijs_1.setEngine)(name, new pkijs_1.CryptoEngine({ name, crypto: crypto }));
|
|
34
62
|
}
|
|
35
63
|
};
|
|
64
|
+
const getCertificateInfo = (certificate, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
|
+
const publicKeyJWK = yield (0, exports.getCertificateSubjectPublicKeyJWK)(certificate);
|
|
66
|
+
return {
|
|
67
|
+
issuer: { dn: (0, exports.getIssuerDN)(certificate) },
|
|
68
|
+
subject: {
|
|
69
|
+
dn: (0, exports.getSubjectDN)(certificate),
|
|
70
|
+
subjectAlternativeNames: (0, exports.getSubjectAlternativeNames)(certificate, { typeFilter: opts === null || opts === void 0 ? void 0 : opts.sanTypeFilter }),
|
|
71
|
+
},
|
|
72
|
+
publicKeyJWK: publicKeyJWK,
|
|
73
|
+
notBefore: certificate.notBefore.value,
|
|
74
|
+
notAfter: certificate.notAfter.value,
|
|
75
|
+
// certificate
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
exports.getCertificateInfo = getCertificateInfo;
|
|
36
79
|
/**
|
|
37
80
|
*
|
|
38
81
|
* @param pemOrDerChain The order must be that the Certs signing another cert must come one after another. So first the signing cert, then any cert signing that cert and so on
|
|
@@ -40,8 +83,13 @@ const defaultCryptoEngine = () => {
|
|
|
40
83
|
* @param verificationTime
|
|
41
84
|
* @param opts
|
|
42
85
|
*/
|
|
43
|
-
const validateX509CertificateChain = (_a) => __awaiter(void 0, [_a], void 0, function* ({ chain: pemOrDerChain, trustAnchors, verificationTime = new Date(), opts = {
|
|
44
|
-
|
|
86
|
+
const validateX509CertificateChain = (_a) => __awaiter(void 0, [_a], void 0, function* ({ chain: pemOrDerChain, trustAnchors, verificationTime = new Date(), opts = {
|
|
87
|
+
trustRootWhenNoAnchors: false,
|
|
88
|
+
allowSingleNoCAChainElement: true,
|
|
89
|
+
blindlyTrustedAnchors: [],
|
|
90
|
+
}, }) {
|
|
91
|
+
var _b;
|
|
92
|
+
const { trustRootWhenNoAnchors = false, allowSingleNoCAChainElement = true, blindlyTrustedAnchors = [], client } = opts;
|
|
45
93
|
const trustedPEMs = trustRootWhenNoAnchors && !trustAnchors ? [pemOrDerChain[pemOrDerChain.length - 1]] : trustAnchors;
|
|
46
94
|
if (pemOrDerChain.length === 0) {
|
|
47
95
|
return {
|
|
@@ -54,40 +102,52 @@ const validateX509CertificateChain = (_a) => __awaiter(void 0, [_a], void 0, fun
|
|
|
54
102
|
const certs = pemOrDerChain.map(x509_utils_1.pemOrDerToX509Certificate);
|
|
55
103
|
const trustedCerts = trustedPEMs ? trustedPEMs.map(x509_utils_1.pemOrDerToX509Certificate) : undefined;
|
|
56
104
|
defaultCryptoEngine();
|
|
105
|
+
if (pemOrDerChain.length === 1) {
|
|
106
|
+
const singleCert = typeof pemOrDerChain[0] === 'string' ? pemOrDerChain[0] : u8a.toString(pemOrDerChain[0], 'base64pad');
|
|
107
|
+
const cert = (0, x509_utils_1.pemOrDerToX509Certificate)(singleCert);
|
|
108
|
+
if (client) {
|
|
109
|
+
const validation = yield (0, exports.validateCertificateChainMatchesClientIdScheme)(cert, client.clientId, client.clientIdScheme);
|
|
110
|
+
if (validation.error) {
|
|
111
|
+
return validation;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (blindlyTrustedAnchors.includes(singleCert)) {
|
|
115
|
+
console.log(`Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`);
|
|
116
|
+
return Object.assign({ error: false, critical: true, message: `Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`, verificationTime, certificateChain: [yield (0, exports.getCertificateInfo)(cert)] }, (client && { client }));
|
|
117
|
+
}
|
|
118
|
+
if (allowSingleNoCAChainElement) {
|
|
119
|
+
const subjectDN = (0, exports.getSubjectDN)(cert).DN;
|
|
120
|
+
if (!(0, exports.getIssuerDN)(cert).DN || (0, exports.getIssuerDN)(cert).DN === subjectDN) {
|
|
121
|
+
const passed = yield cert.verify();
|
|
122
|
+
return Object.assign({ error: !passed, critical: true, message: `Certificate chain validation for ${subjectDN}: ${passed ? 'successful' : 'failed'}.`, verificationTime, certificateChain: [yield (0, exports.getCertificateInfo)(cert)] }, (client && { client }));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
57
126
|
const validationEngine = new pkijs_1.CertificateChainValidationEngine({
|
|
58
127
|
certs /*crls: [crl1], ocsps: [ocsp1], */,
|
|
59
128
|
checkDate: verificationTime,
|
|
60
129
|
trustedCerts,
|
|
61
130
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
error: true,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
131
|
+
try {
|
|
132
|
+
const verification = yield validationEngine.verify();
|
|
133
|
+
if (!verification.result || !verification.certificatePath) {
|
|
134
|
+
return Object.assign({ error: true, critical: true, message: verification.resultMessage !== '' ? verification.resultMessage : `Certificate chain validation failed.`, verificationTime }, (client && { client }));
|
|
135
|
+
}
|
|
136
|
+
const certPath = verification.certificatePath;
|
|
137
|
+
if (client) {
|
|
138
|
+
const clientIdValidation = yield (0, exports.validateCertificateChainMatchesClientIdScheme)(certs[0], client.clientId, client.clientIdScheme);
|
|
139
|
+
if (clientIdValidation.error) {
|
|
140
|
+
return clientIdValidation;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const certInfos = yield Promise.all(certPath.map((certificate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
144
|
+
return (0, exports.getCertificateInfo)(certificate);
|
|
145
|
+
})));
|
|
146
|
+
return Object.assign({ error: false, critical: false, message: `Certificate chain was valid`, verificationTime, certificateChain: certInfos }, (client && { client }));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return Object.assign({ error: true, critical: true, message: `Certificate chain was invalid, ${(_b = error.message) !== null && _b !== void 0 ? _b : '<unknown error>'}`, verificationTime }, (client && { client }));
|
|
70
150
|
}
|
|
71
|
-
const subtle = (0, pkijs_1.getCrypto)(true).subtle;
|
|
72
|
-
const certPath = verification.certificatePath;
|
|
73
|
-
const certInfos = yield Promise.all(certPath.map((certificate) => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
-
const pk = yield certificate.getPublicKey();
|
|
75
|
-
return {
|
|
76
|
-
issuer: { dn: (0, exports.getIssuerDN)(certificate) },
|
|
77
|
-
subject: { dn: (0, exports.getSubjectDN)(certificate) },
|
|
78
|
-
publicKeyJWK: yield subtle.exportKey('jwk', pk),
|
|
79
|
-
notBefore: certificate.notBefore.value,
|
|
80
|
-
notAfter: certificate.notAfter.value,
|
|
81
|
-
// certificate
|
|
82
|
-
};
|
|
83
|
-
})));
|
|
84
|
-
return {
|
|
85
|
-
error: false,
|
|
86
|
-
critical: false,
|
|
87
|
-
message: `Certificate chain was valid`,
|
|
88
|
-
verificationTime,
|
|
89
|
-
certificateChain: certInfos,
|
|
90
|
-
};
|
|
91
151
|
});
|
|
92
152
|
exports.validateX509CertificateChain = validateX509CertificateChain;
|
|
93
153
|
const rdnmap = {
|
|
@@ -131,4 +191,99 @@ const getDNString = (typesAndValues) => {
|
|
|
131
191
|
.map(([key, value]) => `${key}=${value}`)
|
|
132
192
|
.join(',');
|
|
133
193
|
};
|
|
194
|
+
const getCertificateSubjectPublicKeyJWK = (pemOrDerCert) => __awaiter(void 0, void 0, void 0, function* () {
|
|
195
|
+
const pemOrDerStr = typeof pemOrDerCert === 'string'
|
|
196
|
+
? pemOrDerCert
|
|
197
|
+
: pemOrDerCert instanceof Uint8Array
|
|
198
|
+
? u8a.toString(pemOrDerCert, 'base64pad')
|
|
199
|
+
: pemOrDerCert.toString('base64');
|
|
200
|
+
const pem = (0, x509_utils_1.derToPEM)(pemOrDerStr);
|
|
201
|
+
const certificate = (0, x509_utils_1.pemOrDerToX509Certificate)(pem);
|
|
202
|
+
try {
|
|
203
|
+
const subtle = (0, pkijs_1.getCrypto)(true).subtle;
|
|
204
|
+
const pk = yield certificate.getPublicKey();
|
|
205
|
+
return yield subtle.exportKey('jwk', pk);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.log(`Error in primary get JWK from cert:`, error === null || error === void 0 ? void 0 : error.message);
|
|
209
|
+
}
|
|
210
|
+
return yield js_x509_utils_1.default.toJwk(pem, 'pem');
|
|
211
|
+
});
|
|
212
|
+
exports.getCertificateSubjectPublicKeyJWK = getCertificateSubjectPublicKeyJWK;
|
|
213
|
+
/**
|
|
214
|
+
* otherName [0] OtherName,
|
|
215
|
+
* rfc822Name [1] IA5String,
|
|
216
|
+
* dNSName [2] IA5String,
|
|
217
|
+
* x400Address [3] ORAddress,
|
|
218
|
+
* directoryName [4] Name,
|
|
219
|
+
* ediPartyName [5] EDIPartyName,
|
|
220
|
+
* uniformResourceIdentifier [6] IA5String,
|
|
221
|
+
* iPAddress [7] OCTET STRING,
|
|
222
|
+
* registeredID [8] OBJECT IDENTIFIER }
|
|
223
|
+
*/
|
|
224
|
+
var SubjectAlternativeGeneralName;
|
|
225
|
+
(function (SubjectAlternativeGeneralName) {
|
|
226
|
+
SubjectAlternativeGeneralName[SubjectAlternativeGeneralName["rfc822Name"] = 1] = "rfc822Name";
|
|
227
|
+
SubjectAlternativeGeneralName[SubjectAlternativeGeneralName["dnsName"] = 2] = "dnsName";
|
|
228
|
+
SubjectAlternativeGeneralName[SubjectAlternativeGeneralName["uniformResourceIdentifier"] = 6] = "uniformResourceIdentifier";
|
|
229
|
+
SubjectAlternativeGeneralName[SubjectAlternativeGeneralName["ipAddress"] = 7] = "ipAddress";
|
|
230
|
+
})(SubjectAlternativeGeneralName || (exports.SubjectAlternativeGeneralName = SubjectAlternativeGeneralName = {}));
|
|
231
|
+
const assertCertificateMatchesClientIdScheme = (certificate, clientId, clientIdScheme) => {
|
|
232
|
+
const sans = (0, exports.getSubjectAlternativeNames)(certificate, { clientIdSchemeFilter: clientIdScheme });
|
|
233
|
+
const clientIdMatches = sans.find((san) => san.value === clientId);
|
|
234
|
+
if (!clientIdMatches) {
|
|
235
|
+
throw Error(`Client id scheme ${clientIdScheme} used had no matching subject alternative names in certificate with DN ${(0, exports.getSubjectDN)(certificate).DN}. SANS: ${sans.map((san) => san.value).join(',')}`);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
exports.assertCertificateMatchesClientIdScheme = assertCertificateMatchesClientIdScheme;
|
|
239
|
+
const validateCertificateChainMatchesClientIdScheme = (certificate, clientId, clientIdScheme) => __awaiter(void 0, void 0, void 0, function* () {
|
|
240
|
+
const result = {
|
|
241
|
+
error: true,
|
|
242
|
+
critical: true,
|
|
243
|
+
message: `Client Id ${clientId} was not present in certificate using scheme ${clientIdScheme}`,
|
|
244
|
+
client: {
|
|
245
|
+
clientId,
|
|
246
|
+
clientIdScheme,
|
|
247
|
+
},
|
|
248
|
+
certificateChain: [yield (0, exports.getCertificateInfo)(certificate)],
|
|
249
|
+
verificationTime: new Date(),
|
|
250
|
+
};
|
|
251
|
+
try {
|
|
252
|
+
(0, exports.assertCertificateMatchesClientIdScheme)(certificate, clientId, clientIdScheme);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
result.error = false;
|
|
258
|
+
result.message = `Client Id ${clientId} was present in certificate using scheme ${clientIdScheme}`;
|
|
259
|
+
return result;
|
|
260
|
+
});
|
|
261
|
+
exports.validateCertificateChainMatchesClientIdScheme = validateCertificateChainMatchesClientIdScheme;
|
|
262
|
+
const getSubjectAlternativeNames = (certificate, opts) => {
|
|
263
|
+
var _a, _b;
|
|
264
|
+
let typeFilter;
|
|
265
|
+
if (opts === null || opts === void 0 ? void 0 : opts.clientIdSchemeFilter) {
|
|
266
|
+
typeFilter =
|
|
267
|
+
opts.clientIdSchemeFilter === 'x509_san_dns'
|
|
268
|
+
? [SubjectAlternativeGeneralName.dnsName]
|
|
269
|
+
: [SubjectAlternativeGeneralName.uniformResourceIdentifier];
|
|
270
|
+
}
|
|
271
|
+
else if (opts === null || opts === void 0 ? void 0 : opts.typeFilter) {
|
|
272
|
+
typeFilter = Array.isArray(opts.typeFilter) ? opts.typeFilter : [opts.typeFilter];
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
typeFilter = [SubjectAlternativeGeneralName.dnsName, SubjectAlternativeGeneralName.uniformResourceIdentifier];
|
|
276
|
+
}
|
|
277
|
+
const parsedValue = (_b = (_a = certificate.extensions) === null || _a === void 0 ? void 0 : _a.find((ext) => ext.extnID === pkijs_1.id_SubjectAltName)) === null || _b === void 0 ? void 0 : _b.parsedValue;
|
|
278
|
+
if (!parsedValue) {
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
const altNames = parsedValue.toJSON().altNames;
|
|
282
|
+
return altNames
|
|
283
|
+
.filter((altName) => typeFilter.includes(altName.type))
|
|
284
|
+
.map((altName) => {
|
|
285
|
+
return { type: altName.type, value: altName.value };
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
exports.getSubjectAlternativeNames = getSubjectAlternativeNames;
|
|
134
289
|
//# sourceMappingURL=x509-validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x509-validator.js","sourceRoot":"","sources":["../../src/x509/x509-validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"x509-validator.js","sourceRoot":"","sources":["../../src/x509/x509-validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk-ext.x509-utils",
|
|
3
3
|
"description": "Sphereon SSI-SDK plugin functions for X.509 Certificate handling.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.25.0",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@trust/keyto": "^1.0.1",
|
|
14
14
|
"debug": "^4.3.4",
|
|
15
|
+
"js-x509-utils": "^1.0.7",
|
|
15
16
|
"pkijs": "^3.2.4",
|
|
16
17
|
"uint8arrays": "^3.1.1"
|
|
17
18
|
},
|
|
@@ -36,5 +37,5 @@
|
|
|
36
37
|
"DID",
|
|
37
38
|
"Veramo"
|
|
38
39
|
],
|
|
39
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "ca2cc4d0d45bc7e0b25dccc0068420b33bbc4c47"
|
|
40
41
|
}
|
package/src/x509/x509-utils.ts
CHANGED
|
@@ -166,6 +166,10 @@ export function PEMToDer(pem: string): string {
|
|
|
166
166
|
|
|
167
167
|
export function derToPEM(cert: string, headerKey?: 'PUBLIC KEY' | 'RSA PRIVATE KEY' | 'PRIVATE KEY' | 'CERTIFICATE'): string {
|
|
168
168
|
const key = headerKey ?? 'CERTIFICATE'
|
|
169
|
+
if (cert.includes(key)) {
|
|
170
|
+
// Was already in PEM it seems
|
|
171
|
+
return cert
|
|
172
|
+
}
|
|
169
173
|
const matches = cert.match(/.{1,64}/g)
|
|
170
174
|
if (!matches) {
|
|
171
175
|
throw Error('Invalid cert input value supplied')
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import x509 from 'js-x509-utils'
|
|
2
|
+
import {
|
|
3
|
+
AltName,
|
|
4
|
+
AttributeTypeAndValue,
|
|
5
|
+
Certificate,
|
|
6
|
+
CertificateChainValidationEngine,
|
|
7
|
+
CryptoEngine,
|
|
8
|
+
getCrypto,
|
|
9
|
+
id_SubjectAltName,
|
|
10
|
+
setEngine,
|
|
11
|
+
} from 'pkijs'
|
|
12
|
+
import * as u8a from 'uint8arrays'
|
|
13
|
+
import { derToPEM, pemOrDerToX509Certificate } from './x509-utils'
|
|
3
14
|
|
|
4
15
|
export type DNInfo = {
|
|
5
16
|
DN: string
|
|
6
17
|
attributes: Record<string, string>
|
|
7
18
|
}
|
|
8
19
|
|
|
9
|
-
export type
|
|
20
|
+
export type CertificateInfo = {
|
|
10
21
|
certificate?: any // We need to fix the schema generator for this to be Certificate(Json) from pkijs
|
|
11
22
|
notBefore: Date
|
|
12
23
|
notAfter: Date
|
|
@@ -16,6 +27,7 @@ export type CertInfo = {
|
|
|
16
27
|
}
|
|
17
28
|
subject: {
|
|
18
29
|
dn: DNInfo
|
|
30
|
+
subjectAlternativeNames: SubjectAlternativeName[]
|
|
19
31
|
}
|
|
20
32
|
}
|
|
21
33
|
|
|
@@ -24,7 +36,12 @@ export type X509ValidationResult = {
|
|
|
24
36
|
critical: boolean
|
|
25
37
|
message: string
|
|
26
38
|
verificationTime: Date
|
|
27
|
-
certificateChain?: Array<
|
|
39
|
+
certificateChain?: Array<CertificateInfo>
|
|
40
|
+
client?: {
|
|
41
|
+
// In case client id and scheme were passed in we return them for easy access. It means they are validated
|
|
42
|
+
clientId: string
|
|
43
|
+
clientIdScheme: ClientIdScheme
|
|
44
|
+
}
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
const defaultCryptoEngine = () => {
|
|
@@ -46,6 +63,43 @@ const defaultCryptoEngine = () => {
|
|
|
46
63
|
setEngine(name, new CryptoEngine({ name, crypto: crypto }))
|
|
47
64
|
}
|
|
48
65
|
}
|
|
66
|
+
|
|
67
|
+
export const getCertificateInfo = async (
|
|
68
|
+
certificate: Certificate,
|
|
69
|
+
opts?: {
|
|
70
|
+
sanTypeFilter: SubjectAlternativeGeneralName | SubjectAlternativeGeneralName[]
|
|
71
|
+
}
|
|
72
|
+
): Promise<CertificateInfo> => {
|
|
73
|
+
const publicKeyJWK = await getCertificateSubjectPublicKeyJWK(certificate)
|
|
74
|
+
return {
|
|
75
|
+
issuer: { dn: getIssuerDN(certificate) },
|
|
76
|
+
subject: {
|
|
77
|
+
dn: getSubjectDN(certificate),
|
|
78
|
+
subjectAlternativeNames: getSubjectAlternativeNames(certificate, { typeFilter: opts?.sanTypeFilter }),
|
|
79
|
+
},
|
|
80
|
+
publicKeyJWK: publicKeyJWK,
|
|
81
|
+
notBefore: certificate.notBefore.value,
|
|
82
|
+
notAfter: certificate.notAfter.value,
|
|
83
|
+
// certificate
|
|
84
|
+
} satisfies CertificateInfo
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type X509CertificateChainValidationOpts = {
|
|
88
|
+
// Trust the supplied root from the chain, when no anchors are being passed in.
|
|
89
|
+
trustRootWhenNoAnchors?: boolean
|
|
90
|
+
// Do not perform a chain validation check if the chain only has a single value. This means only the certificate itself will be validated. No chain checks for CA certs will be performed. Only used when the cert has no issuer
|
|
91
|
+
allowSingleNoCAChainElement?: boolean
|
|
92
|
+
// WARNING: Do not use in production
|
|
93
|
+
// Similar to regular trust anchors, but no validation is performed whatsoever. Do not use in production settings! Can be handy with self generated certificates as we perform many validations, making it hard to test with self-signed certs. Only applied in case a chain with 1 element is passed in to really make sure people do not abuse this option
|
|
94
|
+
blindlyTrustedAnchors?: string[]
|
|
95
|
+
|
|
96
|
+
client?: {
|
|
97
|
+
// If provided both are required. Validates the leaf certificate against the clientId and scheme
|
|
98
|
+
clientId: string
|
|
99
|
+
clientIdScheme: ClientIdScheme
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
49
103
|
/**
|
|
50
104
|
*
|
|
51
105
|
* @param pemOrDerChain The order must be that the Certs signing another cert must come one after another. So first the signing cert, then any cert signing that cert and so on
|
|
@@ -57,14 +111,18 @@ export const validateX509CertificateChain = async ({
|
|
|
57
111
|
chain: pemOrDerChain,
|
|
58
112
|
trustAnchors,
|
|
59
113
|
verificationTime = new Date(),
|
|
60
|
-
opts = {
|
|
114
|
+
opts = {
|
|
115
|
+
trustRootWhenNoAnchors: false,
|
|
116
|
+
allowSingleNoCAChainElement: true,
|
|
117
|
+
blindlyTrustedAnchors: [],
|
|
118
|
+
},
|
|
61
119
|
}: {
|
|
62
120
|
chain: (Uint8Array | string)[]
|
|
63
121
|
trustAnchors?: string[]
|
|
64
122
|
verificationTime?: Date
|
|
65
|
-
opts?:
|
|
123
|
+
opts?: X509CertificateChainValidationOpts
|
|
66
124
|
}): Promise<X509ValidationResult> => {
|
|
67
|
-
const { trustRootWhenNoAnchors = false } = opts
|
|
125
|
+
const { trustRootWhenNoAnchors = false, allowSingleNoCAChainElement = true, blindlyTrustedAnchors = [], client } = opts
|
|
68
126
|
const trustedPEMs = trustRootWhenNoAnchors && !trustAnchors ? [pemOrDerChain[pemOrDerChain.length - 1]] : trustAnchors
|
|
69
127
|
|
|
70
128
|
if (pemOrDerChain.length === 0) {
|
|
@@ -80,43 +138,88 @@ export const validateX509CertificateChain = async ({
|
|
|
80
138
|
const trustedCerts = trustedPEMs ? trustedPEMs.map(pemOrDerToX509Certificate) : undefined
|
|
81
139
|
defaultCryptoEngine()
|
|
82
140
|
|
|
141
|
+
if (pemOrDerChain.length === 1) {
|
|
142
|
+
const singleCert = typeof pemOrDerChain[0] === 'string' ? pemOrDerChain[0] : u8a.toString(pemOrDerChain[0], 'base64pad')
|
|
143
|
+
const cert = pemOrDerToX509Certificate(singleCert)
|
|
144
|
+
if (client) {
|
|
145
|
+
const validation = await validateCertificateChainMatchesClientIdScheme(cert, client.clientId, client.clientIdScheme)
|
|
146
|
+
if (validation.error) {
|
|
147
|
+
return validation
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (blindlyTrustedAnchors.includes(singleCert)) {
|
|
151
|
+
console.log(`Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`)
|
|
152
|
+
return {
|
|
153
|
+
error: false,
|
|
154
|
+
critical: true,
|
|
155
|
+
message: `Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`,
|
|
156
|
+
verificationTime,
|
|
157
|
+
certificateChain: [await getCertificateInfo(cert)],
|
|
158
|
+
...(client && { client }),
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (allowSingleNoCAChainElement) {
|
|
162
|
+
const subjectDN = getSubjectDN(cert).DN
|
|
163
|
+
if (!getIssuerDN(cert).DN || getIssuerDN(cert).DN === subjectDN) {
|
|
164
|
+
const passed = await cert.verify()
|
|
165
|
+
return {
|
|
166
|
+
error: !passed,
|
|
167
|
+
critical: true,
|
|
168
|
+
message: `Certificate chain validation for ${subjectDN}: ${passed ? 'successful' : 'failed'}.`,
|
|
169
|
+
verificationTime,
|
|
170
|
+
certificateChain: [await getCertificateInfo(cert)],
|
|
171
|
+
...(client && { client }),
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
83
177
|
const validationEngine = new CertificateChainValidationEngine({
|
|
84
178
|
certs /*crls: [crl1], ocsps: [ocsp1], */,
|
|
85
179
|
checkDate: verificationTime,
|
|
86
180
|
trustedCerts,
|
|
87
181
|
})
|
|
88
182
|
|
|
89
|
-
|
|
90
|
-
|
|
183
|
+
try {
|
|
184
|
+
const verification = await validationEngine.verify()
|
|
185
|
+
if (!verification.result || !verification.certificatePath) {
|
|
186
|
+
return {
|
|
187
|
+
error: true,
|
|
188
|
+
critical: true,
|
|
189
|
+
message: verification.resultMessage !== '' ? verification.resultMessage : `Certificate chain validation failed.`,
|
|
190
|
+
verificationTime,
|
|
191
|
+
...(client && { client }),
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const certPath = verification.certificatePath
|
|
195
|
+
if (client) {
|
|
196
|
+
const clientIdValidation = await validateCertificateChainMatchesClientIdScheme(certs[0], client.clientId, client.clientIdScheme)
|
|
197
|
+
if (clientIdValidation.error) {
|
|
198
|
+
return clientIdValidation
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const certInfos: Array<CertificateInfo> = await Promise.all(
|
|
202
|
+
certPath.map(async (certificate) => {
|
|
203
|
+
return getCertificateInfo(certificate)
|
|
204
|
+
})
|
|
205
|
+
)
|
|
206
|
+
return {
|
|
207
|
+
error: false,
|
|
208
|
+
critical: false,
|
|
209
|
+
message: `Certificate chain was valid`,
|
|
210
|
+
verificationTime,
|
|
211
|
+
certificateChain: certInfos,
|
|
212
|
+
...(client && { client }),
|
|
213
|
+
}
|
|
214
|
+
} catch (error: any) {
|
|
91
215
|
return {
|
|
92
216
|
error: true,
|
|
93
217
|
critical: true,
|
|
94
|
-
message:
|
|
218
|
+
message: `Certificate chain was invalid, ${error.message ?? '<unknown error>'}`,
|
|
95
219
|
verificationTime,
|
|
220
|
+
...(client && { client }),
|
|
96
221
|
}
|
|
97
222
|
}
|
|
98
|
-
const subtle = getCrypto(true).subtle
|
|
99
|
-
const certPath = verification.certificatePath
|
|
100
|
-
const certInfos: Array<CertInfo> = await Promise.all(
|
|
101
|
-
certPath.map(async (certificate) => {
|
|
102
|
-
const pk = await certificate.getPublicKey()
|
|
103
|
-
return {
|
|
104
|
-
issuer: { dn: getIssuerDN(certificate) },
|
|
105
|
-
subject: { dn: getSubjectDN(certificate) },
|
|
106
|
-
publicKeyJWK: await subtle.exportKey('jwk', pk),
|
|
107
|
-
notBefore: certificate.notBefore.value,
|
|
108
|
-
notAfter: certificate.notAfter.value,
|
|
109
|
-
// certificate
|
|
110
|
-
} satisfies CertInfo
|
|
111
|
-
})
|
|
112
|
-
)
|
|
113
|
-
return {
|
|
114
|
-
error: false,
|
|
115
|
-
critical: false,
|
|
116
|
-
message: `Certificate chain was valid`,
|
|
117
|
-
verificationTime,
|
|
118
|
-
certificateChain: certInfos,
|
|
119
|
-
}
|
|
120
223
|
}
|
|
121
224
|
|
|
122
225
|
const rdnmap: Record<string, string> = {
|
|
@@ -160,3 +263,116 @@ const getDNString = (typesAndValues: AttributeTypeAndValue[]): string => {
|
|
|
160
263
|
.map(([key, value]) => `${key}=${value}`)
|
|
161
264
|
.join(',')
|
|
162
265
|
}
|
|
266
|
+
|
|
267
|
+
export const getCertificateSubjectPublicKeyJWK = async (pemOrDerCert: string | Uint8Array | Certificate): Promise<JsonWebKey> => {
|
|
268
|
+
const pemOrDerStr =
|
|
269
|
+
typeof pemOrDerCert === 'string'
|
|
270
|
+
? pemOrDerCert
|
|
271
|
+
: pemOrDerCert instanceof Uint8Array
|
|
272
|
+
? u8a.toString(pemOrDerCert, 'base64pad')
|
|
273
|
+
: pemOrDerCert.toString('base64')
|
|
274
|
+
const pem = derToPEM(pemOrDerStr)
|
|
275
|
+
const certificate = pemOrDerToX509Certificate(pem)
|
|
276
|
+
try {
|
|
277
|
+
const subtle = getCrypto(true).subtle
|
|
278
|
+
const pk = await certificate.getPublicKey()
|
|
279
|
+
return await subtle.exportKey('jwk', pk)
|
|
280
|
+
} catch (error: any) {
|
|
281
|
+
console.log(`Error in primary get JWK from cert:`, error?.message)
|
|
282
|
+
}
|
|
283
|
+
return await x509.toJwk(pem, 'pem')
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* otherName [0] OtherName,
|
|
288
|
+
* rfc822Name [1] IA5String,
|
|
289
|
+
* dNSName [2] IA5String,
|
|
290
|
+
* x400Address [3] ORAddress,
|
|
291
|
+
* directoryName [4] Name,
|
|
292
|
+
* ediPartyName [5] EDIPartyName,
|
|
293
|
+
* uniformResourceIdentifier [6] IA5String,
|
|
294
|
+
* iPAddress [7] OCTET STRING,
|
|
295
|
+
* registeredID [8] OBJECT IDENTIFIER }
|
|
296
|
+
*/
|
|
297
|
+
export enum SubjectAlternativeGeneralName {
|
|
298
|
+
rfc822Name = 1, // email
|
|
299
|
+
dnsName = 2,
|
|
300
|
+
uniformResourceIdentifier = 6,
|
|
301
|
+
ipAddress = 7,
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface SubjectAlternativeName {
|
|
305
|
+
value: string
|
|
306
|
+
type: SubjectAlternativeGeneralName
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export type ClientIdScheme = 'x509_san_dns' | 'x509_san_uri'
|
|
310
|
+
|
|
311
|
+
export const assertCertificateMatchesClientIdScheme = (certificate: Certificate, clientId: string, clientIdScheme: ClientIdScheme): void => {
|
|
312
|
+
const sans = getSubjectAlternativeNames(certificate, { clientIdSchemeFilter: clientIdScheme })
|
|
313
|
+
const clientIdMatches = sans.find((san) => san.value === clientId)
|
|
314
|
+
if (!clientIdMatches) {
|
|
315
|
+
throw Error(
|
|
316
|
+
`Client id scheme ${clientIdScheme} used had no matching subject alternative names in certificate with DN ${
|
|
317
|
+
getSubjectDN(certificate).DN
|
|
318
|
+
}. SANS: ${sans.map((san) => san.value).join(',')}`
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export const validateCertificateChainMatchesClientIdScheme = async (
|
|
324
|
+
certificate: Certificate,
|
|
325
|
+
clientId: string,
|
|
326
|
+
clientIdScheme: ClientIdScheme
|
|
327
|
+
): Promise<X509ValidationResult> => {
|
|
328
|
+
const result = {
|
|
329
|
+
error: true,
|
|
330
|
+
critical: true,
|
|
331
|
+
message: `Client Id ${clientId} was not present in certificate using scheme ${clientIdScheme}`,
|
|
332
|
+
client: {
|
|
333
|
+
clientId,
|
|
334
|
+
clientIdScheme,
|
|
335
|
+
},
|
|
336
|
+
certificateChain: [await getCertificateInfo(certificate)],
|
|
337
|
+
verificationTime: new Date(),
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
assertCertificateMatchesClientIdScheme(certificate, clientId, clientIdScheme)
|
|
341
|
+
} catch (error) {
|
|
342
|
+
return result
|
|
343
|
+
}
|
|
344
|
+
result.error = false
|
|
345
|
+
result.message = `Client Id ${clientId} was present in certificate using scheme ${clientIdScheme}`
|
|
346
|
+
return result
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export const getSubjectAlternativeNames = (
|
|
350
|
+
certificate: Certificate,
|
|
351
|
+
opts?: {
|
|
352
|
+
typeFilter?: SubjectAlternativeGeneralName | SubjectAlternativeGeneralName[]
|
|
353
|
+
// When a clientIdchemeFilter is passed in it will always override the above type filter
|
|
354
|
+
clientIdSchemeFilter?: ClientIdScheme
|
|
355
|
+
}
|
|
356
|
+
): SubjectAlternativeName[] => {
|
|
357
|
+
let typeFilter: SubjectAlternativeGeneralName[]
|
|
358
|
+
if (opts?.clientIdSchemeFilter) {
|
|
359
|
+
typeFilter =
|
|
360
|
+
opts.clientIdSchemeFilter === 'x509_san_dns'
|
|
361
|
+
? [SubjectAlternativeGeneralName.dnsName]
|
|
362
|
+
: [SubjectAlternativeGeneralName.uniformResourceIdentifier]
|
|
363
|
+
} else if (opts?.typeFilter) {
|
|
364
|
+
typeFilter = Array.isArray(opts.typeFilter) ? opts.typeFilter : [opts.typeFilter]
|
|
365
|
+
} else {
|
|
366
|
+
typeFilter = [SubjectAlternativeGeneralName.dnsName, SubjectAlternativeGeneralName.uniformResourceIdentifier]
|
|
367
|
+
}
|
|
368
|
+
const parsedValue = certificate.extensions?.find((ext) => ext.extnID === id_SubjectAltName)?.parsedValue as AltName
|
|
369
|
+
if (!parsedValue) {
|
|
370
|
+
return []
|
|
371
|
+
}
|
|
372
|
+
const altNames = parsedValue.toJSON().altNames
|
|
373
|
+
return altNames
|
|
374
|
+
.filter((altName) => typeFilter.includes(altName.type))
|
|
375
|
+
.map((altName) => {
|
|
376
|
+
return { type: altName.type, value: altName.value } satisfies SubjectAlternativeName
|
|
377
|
+
})
|
|
378
|
+
}
|