codekingpro/portable-devtools
114k
1"use strict";
2var __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}));
13var __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});
18var __importStar = (this && this.__importStar) || (function () {
19 var ownKeys = function(o) {
20 ownKeys = Object.getOwnPropertyNames || function (o) {
21 var ar = [];
22 for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23 return ar;
24 };
25 return ownKeys(o);
26 };
27 return function (mod) {
28 if (mod && mod.__esModule) return mod;
29 var result = {};
30 if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31 __setModuleDefault(result, mod);
32 return result;
33 };
34})();
35Object.defineProperty(exports, "__esModule", { value: true });
36exports.X509Certificate = exports.EXTENSION_OID_SCT = void 0;
37/*
38Copyright 2023 The Sigstore Authors.
39
40Licensed under the Apache License, Version 2.0 (the "License");
41you may not use this file except in compliance with the License.
42You may obtain a copy of the License at
43
44 http://www.apache.org/licenses/LICENSE-2.0
45
46Unless required by applicable law or agreed to in writing, software
47distributed under the License is distributed on an "AS IS" BASIS,
48WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49See the License for the specific language governing permissions and
50limitations under the License.
51*/
52const asn1_1 = require("../asn1");
53const crypto = __importStar(require("../crypto"));
54const oid_1 = require("../oid");
55const pem = __importStar(require("../pem"));
56const ext_1 = require("./ext");
57const EXTENSION_OID_SUBJECT_KEY_ID = '2.5.29.14';
58const EXTENSION_OID_KEY_USAGE = '2.5.29.15';
59const EXTENSION_OID_SUBJECT_ALT_NAME = '2.5.29.17';
60const EXTENSION_OID_BASIC_CONSTRAINTS = '2.5.29.19';
61const EXTENSION_OID_AUTHORITY_KEY_ID = '2.5.29.35';
62exports.EXTENSION_OID_SCT = '1.3.6.1.4.1.11129.2.4.2';
63class X509Certificate {
64 root;
65 constructor(asn1) {
66 this.root = asn1;
67 }
68 static parse(cert) {
69 const der = typeof cert === 'string' ? pem.toDER(cert) : cert;
70 const asn1 = asn1_1.ASN1Obj.parseBuffer(der);
71 return new X509Certificate(asn1);
72 }
73 get tbsCertificate() {
74 return this.tbsCertificateObj;
75 }
76 get version() {
77 // version number is the first element of the version context specific tag
78 const ver = this.versionObj.subs[0].toInteger();
79 return `v${(ver + BigInt(1)).toString()}`;
80 }
81 get serialNumber() {
82 return this.serialNumberObj.value;
83 }
84 get notBefore() {
85 // notBefore is the first element of the validity sequence
86 return this.validityObj.subs[0].toDate();
87 }
88 get notAfter() {
89 // notAfter is the second element of the validity sequence
90 return this.validityObj.subs[1].toDate();
91 }
92 get issuer() {
93 return this.issuerObj.value;
94 }
95 get subject() {
96 return this.subjectObj.value;
97 }
98 get publicKey() {
99 return this.subjectPublicKeyInfoObj.toDER();
100 }
101 get signatureAlgorithm() {
102 const oid = this.signatureAlgorithmObj.subs[0].toOID();
103 if (oid_1.RSA_SIGNATURE_ALGOS[oid]) {
104 return oid_1.RSA_SIGNATURE_ALGOS[oid];
105 }
106 return oid_1.ECDSA_SIGNATURE_ALGOS[oid];
107 }
108 get signatureValue() {
109 // Signature value is a bit string, so we need to skip the first byte
110 return this.signatureValueObj.value.subarray(1);
111 }
112 get subjectAltName() {
113 const ext = this.extSubjectAltName;
114 return ext?.uri || /* istanbul ignore next */ ext?.rfc822Name;
115 }
116 get extensions() {
117 // The extension list is the first (and only) element of the extensions
118 // context specific tag
119 /* istanbul ignore next */
120 const extSeq = this.extensionsObj?.subs[0];
121 /* istanbul ignore next */
122 return extSeq?.subs || [];
123 }
124 get extKeyUsage() {
125 const ext = this.findExtension(EXTENSION_OID_KEY_USAGE);
126 return ext ? new ext_1.X509KeyUsageExtension(ext) : undefined;
127 }
128 get extBasicConstraints() {
129 const ext = this.findExtension(EXTENSION_OID_BASIC_CONSTRAINTS);
130 return ext ? new ext_1.X509BasicConstraintsExtension(ext) : undefined;
131 }
132 get extSubjectAltName() {
133 const ext = this.findExtension(EXTENSION_OID_SUBJECT_ALT_NAME);
134 return ext ? new ext_1.X509SubjectAlternativeNameExtension(ext) : undefined;
135 }
136 get extAuthorityKeyID() {
137 const ext = this.findExtension(EXTENSION_OID_AUTHORITY_KEY_ID);
138 return ext ? new ext_1.X509AuthorityKeyIDExtension(ext) : undefined;
139 }
140 get extSubjectKeyID() {
141 const ext = this.findExtension(EXTENSION_OID_SUBJECT_KEY_ID);
142 return ext
143 ? new ext_1.X509SubjectKeyIDExtension(ext)
144 : /* istanbul ignore next */ undefined;
145 }
146 get extSCT() {
147 const ext = this.findExtension(exports.EXTENSION_OID_SCT);
148 return ext ? new ext_1.X509SCTExtension(ext) : undefined;
149 }
150 get isCA() {
151 const ca = this.extBasicConstraints?.isCA || false;
152 // If the KeyUsage extension is present, keyCertSign must be set
153 /* istanbul ignore else */
154 if (this.extKeyUsage) {
155 return ca && this.extKeyUsage.keyCertSign;
156 }
157 // TODO: test coverage for this case
158 /* istanbul ignore next */
159 return ca;
160 }
161 extension(oid) {
162 const ext = this.findExtension(oid);
163 return ext ? new ext_1.X509Extension(ext) : undefined;
164 }
165 verify(issuerCertificate) {
166 // Use the issuer's public key if provided, otherwise use the subject's
167 const publicKey = issuerCertificate?.publicKey || this.publicKey;
168 const key = crypto.createPublicKey(publicKey);
169 return crypto.verify(this.tbsCertificate.toDER(), key, this.signatureValue, this.signatureAlgorithm);
170 }
171 validForDate(date) {
172 return this.notBefore <= date && date <= this.notAfter;
173 }
174 equals(other) {
175 return this.root.toDER().equals(other.root.toDER());
176 }
177 // Creates a copy of the certificate with a new buffer
178 clone() {
179 const der = this.root.toDER();
180 const clone = Buffer.alloc(der.length);
181 der.copy(clone);
182 return X509Certificate.parse(clone);
183 }
184 findExtension(oid) {
185 // Find the extension with the given OID. The OID will always be the first
186 // element of the extension sequence
187 return this.extensions.find((ext) => ext.subs[0].toOID() === oid);
188 }
189 /////////////////////////////////////////////////////////////////////////////
190 // The following properties use the documented x509 structure to locate the
191 // desired ASN.1 object
192 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1
193 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.1
194 get tbsCertificateObj() {
195 // tbsCertificate is the first element of the certificate sequence
196 return this.root.subs[0];
197 }
198 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2
199 get signatureAlgorithmObj() {
200 // signatureAlgorithm is the second element of the certificate sequence
201 return this.root.subs[1];
202 }
203 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.3
204 get signatureValueObj() {
205 // signatureValue is the third element of the certificate sequence
206 return this.root.subs[2];
207 }
208 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1
209 get versionObj() {
210 // version is the first element of the tbsCertificate sequence
211 return this.tbsCertificateObj.subs[0];
212 }
213 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2
214 get serialNumberObj() {
215 // serialNumber is the second element of the tbsCertificate sequence
216 return this.tbsCertificateObj.subs[1];
217 }
218 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.4
219 get issuerObj() {
220 // issuer is the fourth element of the tbsCertificate sequence
221 return this.tbsCertificateObj.subs[3];
222 }
223 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5
224 get validityObj() {
225 // version is the fifth element of the tbsCertificate sequence
226 return this.tbsCertificateObj.subs[4];
227 }
228 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.6
229 get subjectObj() {
230 // subject is the sixth element of the tbsCertificate sequence
231 return this.tbsCertificateObj.subs[5];
232 }
233 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7
234 get subjectPublicKeyInfoObj() {
235 // subjectPublicKeyInfo is the seventh element of the tbsCertificate sequence
236 return this.tbsCertificateObj.subs[6];
237 }
238 // Extensions can't be located by index because their position varies. Instead,
239 // we need to find the extensions context specific tag
240 // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.9
241 get extensionsObj() {
242 return this.tbsCertificateObj.subs.find((sub) => sub.tag.isContextSpecific(0x03));
243 }
244}
245exports.X509Certificate = X509Certificate;
246 