1"use strict"; 2Object.defineProperty(exports, "__esModule", { value: true }); 3exports.x509SCTExtension = exports.x509SubjectKeyIDExtension = exports.x509AuthorityKeyIDExtension = exports.x509SubjectAlternativeNameExtension = exports.x509KeyUsageExtension = exports.x509BasicConstraintsExtension = exports.x509Extension = void 0; 4const stream_1 = require("../util/stream"); 5const sct_1 = require("./sct"); 6// https://www.rfc-editor.org/rfc/rfc5280#section-4.1 7class x509Extension { 8 constructor(asn1) { 9 this.root = asn1; 10 } 11 get oid() { 12 return this.root.subs[0].toOID(); 13 } 14 get critical() { 15 // The critical field is optional and will be the second element of the 16 // extension sequence if present. Default to false if not present. 17 return this.root.subs.length === 3 ? this.root.subs[1].toBoolean() : false; 18 } 19 get value() { 20 return this.extnValueObj.value; 21 } 22 get valueObj() { 23 return this.extnValueObj; 24 } 25 get extnValueObj() { 26 // The extnValue field will be the last element of the extension sequence 27 return this.root.subs[this.root.subs.length - 1]; 28 } 29} 30exports.x509Extension = x509Extension; 31// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9 32class x509BasicConstraintsExtension extends x509Extension { 33 get isCA() { 34 return this.sequence.subs[0].toBoolean(); 35 } 36 get pathLenConstraint() { 37 return this.sequence.subs.length > 1 38 ? this.sequence.subs[1].toInteger() 39 : undefined; 40 } 41 // The extnValue field contains a single sequence wrapping the isCA and 42 // pathLenConstraint. 43 get sequence() { 44 return this.extnValueObj.subs[0]; 45 } 46} 47exports.x509BasicConstraintsExtension = x509BasicConstraintsExtension; 48// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3 49class x509KeyUsageExtension extends x509Extension { 50 get digitalSignature() { 51 return this.bitString[0] === 1; 52 } 53 get keyCertSign() { 54 return this.bitString[5] === 1; 55 } 56 get crlSign() { 57 return this.bitString[6] === 1; 58 } 59 // The extnValue field contains a single bit string which is a bit mask 60 // indicating which key usages are enabled. 61 get bitString() { 62 return this.extnValueObj.subs[0].toBitString(); 63 } 64} 65exports.x509KeyUsageExtension = x509KeyUsageExtension; 66// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 67class x509SubjectAlternativeNameExtension extends x509Extension { 68 get rfc822Name() { 69 return this.findGeneralName(0x01)?.value.toString('ascii'); 70 } 71 get uri() { 72 return this.findGeneralName(0x06)?.value.toString('ascii'); 73 } 74 // Retrieve the value of an otherName with the given OID. 75 otherName(oid) { 76 const otherName = this.findGeneralName(0x00); 77 if (otherName === undefined) { 78 return undefined; 79 } 80 // The otherName is a sequence containing an OID and a value. 81 // Need to check that the OID matches the one we're looking for. 82 const otherNameOID = otherName.subs[0].toOID(); 83 if (otherNameOID !== oid) { 84 return undefined; 85 } 86 // The otherNameValue is a sequence containing the actual value. 87 const otherNameValue = otherName.subs[1]; 88 return otherNameValue.subs[0].value.toString('ascii'); 89 } 90 findGeneralName(tag) { 91 return this.generalNames.find((gn) => gn.tag.isContextSpecific(tag)); 92 } 93 // The extnValue field contains a sequence of GeneralNames. 94 get generalNames() { 95 return this.extnValueObj.subs[0].subs; 96 } 97} 98exports.x509SubjectAlternativeNameExtension = x509SubjectAlternativeNameExtension; 99// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.1 100class x509AuthorityKeyIDExtension extends x509Extension { 101 get keyIdentifier() { 102 return this.findSequenceMember(0x00)?.value; 103 } 104 findSequenceMember(tag) { 105 return this.sequence.subs.find((el) => el.tag.isContextSpecific(tag)); 106 } 107 // The extnValue field contains a single sequence wrapping the keyIdentifier 108 get sequence() { 109 return this.extnValueObj.subs[0]; 110 } 111} 112exports.x509AuthorityKeyIDExtension = x509AuthorityKeyIDExtension; 113// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2 114class x509SubjectKeyIDExtension extends x509Extension { 115 get keyIdentifier() { 116 return this.extnValueObj.subs[0].value; 117 } 118} 119exports.x509SubjectKeyIDExtension = x509SubjectKeyIDExtension; 120// https://www.rfc-editor.org/rfc/rfc6962#section-3.3 121class x509SCTExtension extends x509Extension { 122 constructor(asn1) { 123 super(asn1); 124 } 125 get signedCertificateTimestamps() { 126 const buf = this.extnValueObj.subs[0].value; 127 const stream = new stream_1.ByteStream(buf); 128 // The overall list length is encoded in the first two bytes -- note this 129 // is the length of the list in bytes, NOT the number of SCTs in the list 130 const end = stream.getUint16() + 2; 131 const sctList = []; 132 while (stream.position < end) { 133 // Read the length of the next SCT 134 const sctLength = stream.getUint16(); 135 // Slice out the bytes for the next SCT and parse it 136 const sct = stream.getBlock(sctLength); 137 sctList.push(sct_1.SignedCertificateTimestamp.parse(sct)); 138 } 139 if (stream.position !== end) { 140 throw new Error('SCT list length does not match actual length'); 141 } 142 return sctList; 143 } 144} 145exports.x509SCTExtension = x509SCTExtension; 146