trusted-issuer-registry
Version:
Registry of trusted credential issuers
2 lines (1 loc) • 4.82 kB
JavaScript
import*as e from"asn1js";import{Certificate as r}from"pkijs";import t from"canonical-json";const n="0.1",a=`https://cdn.jsdelivr.net/npm/trusted-issuer-registry@${n}`,s=`${a}/test`,verifySignatureWithPem=async(t,n,a)=>{try{const s=base64ToUint8Array(t.replace(/-----BEGIN [^-]+-----/,"").replace(/-----END [^-]+-----/,"").replace(/\s+/g,"")),o=e.fromBER(s.buffer),i=new r({schema:o.result}).subjectPublicKeyInfo;if(!i||!i.algorithm||!i.algorithm.algorithmId)throw console.error("Parsed publicKeyInfo:",i),new Error("Could not extract algorithm information from public key");const c=function(e){const r=e.algorithm.algorithmId,t=e.algorithm.algorithmParams;let n;if(r&&"object"==typeof r&&r.valueBlock&&"function"==typeof r.valueBlock.toString)n=r.valueBlock.toString();else{if("string"!=typeof r)throw new Error("Unsupported algorithmOid format");n=r}switch(n){case"1.2.840.10045.2.1":let e;switch(e=t&&"object"==typeof t&&t.valueBlock&&"function"==typeof t.valueBlock.toString?t.valueBlock.toString():"string"==typeof t?t:void 0,e){case"1.2.840.10045.3.1.7":return{name:"ECDSA",namedCurve:"P-256",hash:{name:"SHA-256"}};case"1.3.132.0.34":return{name:"ECDSA",namedCurve:"P-384",hash:{name:"SHA-384"}};case"1.3.132.0.35":return{name:"ECDSA",namedCurve:"P-521",hash:{name:"SHA-512"}};case void 0:return{name:"ECDSA",namedCurve:"P-256",hash:{name:"SHA-256"}};default:throw new Error(`Unsupported EC curve: ${e}`)}case"1.2.840.113549.1.1.1":return{name:"RSASSA-PKCS1-v1_5"};case"1.2.840.113549.1.1.10":return{name:"RSA-PSS"};default:throw new Error(`Unsupported algorithm OID: ${n}`)}}(i),u=i.toSchema().toBER(),l=await crypto.subtle.importKey("spki",u,c,!1,["verify"]);let h;if("ECDSA"===c.name){let r=32;"P-384"===c.namedCurve&&(r=48),"P-521"===c.namedCurve&&(r=66),h=function(r,t){try{const n=base64ToUint8Array(r),a=e.fromBER(n.buffer);if(2!==a.result.valueBlock.value.length)throw new Error("Invalid DER signature structure");const s=a.result.valueBlock.value[0],o=a.result.valueBlock.value[1],i=new Uint8Array(s.valueBlock.valueHex),c=new Uint8Array(o.valueBlock.valueHex),u=padOrTrimUint8Array(i,t),l=padOrTrimUint8Array(c,t),h=new Uint8Array(2*t);return h.set(u,0),h.set(l,t),h.buffer}catch(e){throw console.error("Error converting DER signature to raw:",e),e}}(n,r)}else h=base64ToUint8Array(n).buffer;return await crypto.subtle.verify(c,l,h,a)}catch(e){throw console.error("Error converting PEM to SPKI key:",e),e}};function base64ToUint8Array(e){if("function"==typeof Buffer)return new Uint8Array(Buffer.from(e,"base64"));{const r=atob(e),t=new Uint8Array(r.length);for(let e=0;e<r.length;e++)t[e]=r.charCodeAt(e);return t}}function padOrTrimUint8Array(e,r){if(e.length===r)return e;if(e.length>r)return e.slice(e.length-r);const t=new Uint8Array(r);return t.set(e,r-e.length),t}class TrustedIssuerRegistry{constructor(e={}){this._cacheEnabled=e.cacheEnabled??!0,this._cacheTTL=e.cacheTTL??864e5,this._urlBase=e.useTestData?s:a,this._cache={}}async getEndOfLifeDate(){const e=await fetch(`${this._urlBase}/deprecation_notice.json`);if(e.ok){const r=await e.json();if(!r.version)return null;const[t,a]=r.version.split(".").map(Number),[s,o]=n.split(".").map(Number);return t<s||t===s&&a<o?null:new Date(1e3*r.end_of_life)}return null}async getIssuerFromX509AKI(e){if(this._cacheEnabled&&e in this._cache&&this._cache[e].expiresAt>Date.now())return this._deepCopy(this._cache[e].issuer);const r=await fetch(`${this._urlBase}/issuers/x509_aki/${e}.json`);if(r.ok){const t=await r.json();return await this._verifyIssuer(t)?(this._cacheEnabled&&(this._cache[e]={issuer:t,expiresAt:Date.now()+this._cacheTTL}),this._deepCopy(t)):null}return this._cacheEnabled&&(this._cache[e]={issuer:null,expiresAt:Date.now()+this._cacheTTL}),null}async _verifyIssuer(e){const r={...e},n=r.signature;delete r.signature;const a=t(r);let s=!1;try{const e=(new TextEncoder).encode(a).buffer;s=await verifySignatureWithPem("-----BEGIN CERTIFICATE-----\nMIIBnDCCAUGgAwIBAgIUekpHX8hoNIrffOfU7MBBNgLJQ2IwCgYIKoZIzj0EAwIw\nIzEhMB8GA1UEAwwYVW5pdmVyc2FsIFZlcmlmeSBSb290IENBMB4XDTI1MDgwNzE4\nMDMwOVoXDTM1MDgwNTE4MDMwOVowIzEhMB8GA1UEAwwYVW5pdmVyc2FsIFZlcmlm\neSBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/dMNQXfYuLMvGYfU\nz/j1jj0GsmT3ysLcxNbN/fJ9JPjgfRPrq3XxbbgT0evxBBp0s124xGQw3rohL9+B\nt6JahqNTMFEwHQYDVR0OBBYEFHPcZW9gI99hWaLBRZUgX+TbICyCMB8GA1UdIwQY\nMBaAFHPcZW9gI99hWaLBRZUgX+TbICyCMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZI\nzj0EAwIDSQAwRgIhAKVKMO3AAWQsCUSQUbhBipi9bTJCBBqF65I8BmfSyqGNAiEA\n7GWs56atbaun83KIokEG9xXhPXGkH6/XWk+eioyyoFo=\n-----END CERTIFICATE-----",n,e)}catch(e){console.error("Issuer signature verification failed",e)}return s}_deepCopy(e){return JSON.parse(JSON.stringify(e))}static minorVersion=n}TrustedIssuerRegistry.verifySignatureWithPem=verifySignatureWithPem;export{TrustedIssuerRegistry as default,verifySignatureWithPem};