micro509 0.1.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.
Files changed (115) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +220 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.js +1 -0
  5. package/dist/internal/asn1/asn1.js +2 -0
  6. package/dist/internal/asn1/asn1.js.map +1 -0
  7. package/dist/internal/asn1/der.js +2 -0
  8. package/dist/internal/asn1/der.js.map +1 -0
  9. package/dist/internal/asn1/oids.js +2 -0
  10. package/dist/internal/asn1/oids.js.map +1 -0
  11. package/dist/internal/crypto/algorithm-names.js +2 -0
  12. package/dist/internal/crypto/algorithm-names.js.map +1 -0
  13. package/dist/internal/crypto/ecdsa.js +2 -0
  14. package/dist/internal/crypto/ecdsa.js.map +1 -0
  15. package/dist/internal/crypto/hash.js +2 -0
  16. package/dist/internal/crypto/hash.js.map +1 -0
  17. package/dist/internal/crypto/pbes2.d.ts +23 -0
  18. package/dist/internal/crypto/pbes2.js +2 -0
  19. package/dist/internal/crypto/pbes2.js.map +1 -0
  20. package/dist/internal/crypto/rsa-pss.js +2 -0
  21. package/dist/internal/crypto/rsa-pss.js.map +1 -0
  22. package/dist/internal/crypto/sig-verify.js +2 -0
  23. package/dist/internal/crypto/sig-verify.js.map +1 -0
  24. package/dist/internal/crypto/signing.d.ts +16 -0
  25. package/dist/internal/crypto/signing.js +2 -0
  26. package/dist/internal/crypto/signing.js.map +1 -0
  27. package/dist/internal/crypto/webcrypto.js +2 -0
  28. package/dist/internal/crypto/webcrypto.js.map +1 -0
  29. package/dist/internal/shared/base64.js +2 -0
  30. package/dist/internal/shared/base64.js.map +1 -0
  31. package/dist/internal/shared/dn.js +2 -0
  32. package/dist/internal/shared/dn.js.map +1 -0
  33. package/dist/internal/shared/ip.js +2 -0
  34. package/dist/internal/shared/ip.js.map +1 -0
  35. package/dist/internal/verify/name-constraints-engine.js +2 -0
  36. package/dist/internal/verify/name-constraints-engine.js.map +1 -0
  37. package/dist/internal/verify/policy-engine.js +2 -0
  38. package/dist/internal/verify/policy-engine.js.map +1 -0
  39. package/dist/internal/verify/verify-path.js +2 -0
  40. package/dist/internal/verify/verify-path.js.map +1 -0
  41. package/dist/internal/x509/extension-bits.d.ts +18 -0
  42. package/dist/internal/x509/extension-bits.js +2 -0
  43. package/dist/internal/x509/extension-bits.js.map +1 -0
  44. package/dist/internal/x509/extension-registry.js +2 -0
  45. package/dist/internal/x509/extension-registry.js.map +1 -0
  46. package/dist/internal/x509/name-fields.js +2 -0
  47. package/dist/internal/x509/name-fields.js.map +1 -0
  48. package/dist/keys/keys.d.ts +431 -0
  49. package/dist/keys/keys.js +5 -0
  50. package/dist/keys/keys.js.map +1 -0
  51. package/dist/keys.d.ts +3 -0
  52. package/dist/keys.js +1 -0
  53. package/dist/pem/pem.d.ts +56 -0
  54. package/dist/pem/pem.js +6 -0
  55. package/dist/pem/pem.js.map +1 -0
  56. package/dist/pem.d.ts +2 -0
  57. package/dist/pem.js +1 -0
  58. package/dist/pkcs/pfx.d.ts +177 -0
  59. package/dist/pkcs/pfx.js +2 -0
  60. package/dist/pkcs/pfx.js.map +1 -0
  61. package/dist/pkcs/pkcs12-mac.d.ts +41 -0
  62. package/dist/pkcs/pkcs12-mac.js +2 -0
  63. package/dist/pkcs/pkcs12-mac.js.map +1 -0
  64. package/dist/pkcs/pkcs7.d.ts +131 -0
  65. package/dist/pkcs/pkcs7.js +2 -0
  66. package/dist/pkcs/pkcs7.js.map +1 -0
  67. package/dist/pkcs.d.ts +5 -0
  68. package/dist/pkcs.js +1 -0
  69. package/dist/result/result.d.ts +68 -0
  70. package/dist/result/result.js +2 -0
  71. package/dist/result/result.js.map +1 -0
  72. package/dist/result.d.ts +2 -0
  73. package/dist/result.js +1 -0
  74. package/dist/revocation/chain.d.ts +180 -0
  75. package/dist/revocation/chain.js +2 -0
  76. package/dist/revocation/chain.js.map +1 -0
  77. package/dist/revocation/crl.d.ts +316 -0
  78. package/dist/revocation/crl.js +2 -0
  79. package/dist/revocation/crl.js.map +1 -0
  80. package/dist/revocation/ocsp.d.ts +332 -0
  81. package/dist/revocation/ocsp.js +2 -0
  82. package/dist/revocation/ocsp.js.map +1 -0
  83. package/dist/revocation/revocation.d.ts +168 -0
  84. package/dist/revocation/revocation.js +2 -0
  85. package/dist/revocation/revocation.js.map +1 -0
  86. package/dist/revocation.d.ts +5 -0
  87. package/dist/revocation.js +1 -0
  88. package/dist/verify/identity.d.ts +129 -0
  89. package/dist/verify/identity.js +2 -0
  90. package/dist/verify/identity.js.map +1 -0
  91. package/dist/verify/name-constraints.d.ts +18 -0
  92. package/dist/verify/policy.d.ts +39 -0
  93. package/dist/verify/verify.d.ts +404 -0
  94. package/dist/verify/verify.js +2 -0
  95. package/dist/verify/verify.js.map +1 -0
  96. package/dist/verify.d.ts +5 -0
  97. package/dist/verify.js +1 -0
  98. package/dist/x509/certificate.d.ts +191 -0
  99. package/dist/x509/certificate.js +2 -0
  100. package/dist/x509/certificate.js.map +1 -0
  101. package/dist/x509/csr.d.ts +55 -0
  102. package/dist/x509/csr.js +2 -0
  103. package/dist/x509/csr.js.map +1 -0
  104. package/dist/x509/extensions.d.ts +550 -0
  105. package/dist/x509/extensions.js +2 -0
  106. package/dist/x509/extensions.js.map +1 -0
  107. package/dist/x509/name.d.ts +140 -0
  108. package/dist/x509/name.js +2 -0
  109. package/dist/x509/name.js.map +1 -0
  110. package/dist/x509/parse.d.ts +377 -0
  111. package/dist/x509/parse.js +2 -0
  112. package/dist/x509/parse.js.map +1 -0
  113. package/dist/x509.d.ts +8 -0
  114. package/dist/x509.js +1 -0
  115. package/package.json +153 -0
@@ -0,0 +1,2 @@
1
+ import{bitString as e,concatBytes as t,explicitContext as n,implicitPrimitiveContext as r,integer as i,nullValue as a,objectIdentifier as o,octetString as s,readElement as c,readRootElement as l,readSequenceChildren as u,sequence as d,time as f,tlv as p}from"../internal/asn1/der.js";import{childrenOf as m,decodeNonNegativeIntegerNumber as h,decodeObjectIdentifier as g,decodeString as _,extractBitStringValue as v,hexToBytes as y,parseTime as b,requireElement as x,toArrayBuffer as S,toHex as C}from"../internal/asn1/asn1.js";import{OIDS as w}from"../internal/asn1/oids.js";import{getCrypto as T}from"../internal/crypto/webcrypto.js";import{base64Encode as E}from"../internal/shared/base64.js";import{pemDecode as D,pemEncode as O}from"../pem/pem.js";import{describeHashAlgorithm as k,describeSignatureAlgorithm as ee}from"../internal/crypto/algorithm-names.js";import{parseCertificateDer as A,parseCertificateFromSource as j}from"../x509/parse.js";import{verifySignedDataDetailed as te}from"../internal/crypto/sig-verify.js";import{compareDistinguishedNames as M}from"../internal/shared/dn.js";import{encodeAlgorithmIdentifier as ne,getSignatureAlgorithm as re,signBytes as ie}from"../internal/crypto/signing.js";import{verifyCertificateChain as ae}from"../verify/verify.js";async function oe(e){let t=e.hashAlgorithm??`SHA-1`,r=[];for(let n of e.requests){let e=await K(n.certificate),i=await K(n.issuerCertificate);r.push(d([await U(e,i,t)]))}let i=[d(r)];e.nonce!==void 0&&i.push(n(2,d([d([o(w.ocspNonce),s(s(e.nonce))])])));let a=d([d(i)]);return{der:a,pem:O(`OCSP REQUEST`,a),base64:E(a)}}function N(e){let t=u(e,{maxDepth:64});if(t.length<1||t.length>2)throw Error(`Malformed OCSP request`);let n=x(t[0],`tbsRequest`),r=t[1];if(r!==void 0&&r.tag!==160)throw Error(`Malformed OCSP request`);r!==void 0&&Me(e,r);let i=m(e,n),a=0;if(i[a]?.tag===160){let t=m(e,x(i[a],`version`)),n=x(t[0],`version`);if(t.length!==1||n.tag!==2)throw Error(`version must use INTEGER`);if(h(n.value,`OCSP request version`)!==0)throw Error(`Unsupported OCSP request version`);a+=1}let o=i[a];o?.tag===161&&(je(e,o),a+=1);let s=x(i[a],`requestList`);if(s.tag!==48)throw Error(`requestList must use SEQUENCE`);if(m(e,s).length===0)throw Error(`requestList must not be empty`);let c=m(e,s).map(t=>{let n=m(e,t);if(n.length<1||n.length>2||n[1]!==void 0&&n[1].tag!==160)throw Error(`Malformed OCSP request entry`);let r=x(n[0],`reqCert`);return q(e.slice(r.start-r.headerLength,r.end))});a+=1;let l=i[a];if(l!==void 0&&l.tag!==162||i.length!==a+(l===void 0?0:1))throw Error(`Malformed OCSP request`);let d=l===void 0?void 0:X(e,l);return{der:new Uint8Array(e),requests:c,...d===void 0?{}:{nonce:d}}}function P(e){return N(D(`OCSP REQUEST`,e))}function F(e){let t=u(e,{maxDepth:64});if(t.length<1||t.length>2)throw Error(`Malformed OCSP response`);let n=x(t[0],`responseStatus`);if(n.tag!==10)throw Error(`responseStatus must use ENUMERATED`);let r=De(h(n.value,`OCSP responseStatus`)),i=t[1];if(i===void 0)return{der:new Uint8Array(e),responseStatus:r};if(i.tag!==160)throw Error(`Malformed OCSP response`);let a=m(e,i),o=x(a[0],`responseBytes`);if(a.length!==1||o.tag!==48)throw Error(`Malformed OCSP response`);let s=m(e,o);if(s.length!==2)throw Error(`responseBytes must contain responseType and response`);let c=x(s[0],`responseType`),l=x(s[1],`response`);if(l.tag!==4)throw Error(`response must use OCTET STRING`);let d=g(c.value);if(d!==w.ocspBasicResponse)return{der:new Uint8Array(e),responseStatus:r,responseTypeOid:d};let f=l.value,p=u(f);if(p.length<3||p.length>4)throw Error(`Malformed BasicOCSPResponse`);let _=x(p[0],`responseData`),y=x(p[1],`signatureAlgorithm`),b=x(p[2],`signatureValue`),S=p[3];if(S!==void 0&&S.tag!==160)throw Error(`Malformed BasicOCSPResponse`);let C=m(f,y),T=g(x(C[0],`signatureAlgorithm OID`).value),E=C[1],D=f.slice(_.start-_.headerLength,_.end),O=ue(D);return{der:new Uint8Array(e),responseStatus:r,responseTypeOid:d,responseDataDer:D,responderId:O.responderId,signatureAlgorithmOid:T,signatureAlgorithmName:ee(T,E===void 0?void 0:f.slice(E.start-E.headerLength,E.end)),signatureValue:v(b),producedAt:O.producedAt,responses:O.responses,...O.nonce===void 0?{}:{nonce:O.nonce},...S?.tag===160?{certificates:Ee(f,S)}:{}}}function I(e){return F(D(`OCSP RESPONSE`,e))}async function se(i){let a=await K(i.signerCertificate),c=re(i.signerPrivateKey),l=i.producedAt??new Date,u=i.hashAlgorithm??`SHA-1`,m=[];for(let e of i.responses){let t=await K(e.certificate),n=await K(e.issuerCertificate);m.push(await he(t,n,e,u))}let h=[r(2,await G(`SHA-1`,Z(a.subjectPublicKeyInfoDer))),f(l),d(m)];i.nonce!==void 0&&h.push(n(1,d([d([o(w.ocspNonce),s(s(i.nonce))])])));let g=d(h),_=await ie(i.signerPrivateKey,c,g),v=i.includedCertificates===void 0?[]:await Promise.all(i.includedCertificates.map(K)),y=[g,ne(c),e(_)];v.length>0&&y.push(n(0,t(v.map(e=>e.der))));let b=d(y),x=d([p(10,Uint8Array.of(0)),n(0,d([o(w.ocspBasicResponse),s(b)]))]);return{der:x,pem:O(`OCSP RESPONSE`,x),base64:E(x)}}async function L(e,t){let n;try{n=B(e)}catch{return R(`signature_invalid`,`OCSP response signed content is malformed`)}if(n.responseDataDer===void 0||n.signatureAlgorithmOid===void 0||n.signatureValue===void 0)return R(`signature_invalid`,`OCSP response is not signed`);let r;try{r=await K(t)}catch{return R(`signature_invalid`,`OCSP signer certificate input is malformed`)}let i;try{i=await te(n.signatureAlgorithmOid,void 0,r.publicKeyAlgorithmOid,r.publicKeyParametersOid,r.subjectPublicKeyInfoDer,n.signatureValue,n.responseDataDer)}catch{return R(`signature_invalid`,`OCSP response signature verification failed`)}return i.ok?i.valid?{ok:!0,value:n}:R(`signature_invalid`,`OCSP response signature does not verify`):i.code===`verification_error`?R(`signature_invalid`,`OCSP response signature verification failed`):R(`signature_invalid`,`OCSP response signature uses unsupported algorithm parameters`)}async function ce(e){let t;try{t=B(e.response)}catch{return z(`signature_invalid`,`OCSP response signed content is malformed`)}if(t.responseStatus!==`successful`)return z(`response_status_invalid`,`OCSP response status is ${t.responseStatus}`);let n;try{n=await K(e.issuerCertificate)}catch{return z(`signature_invalid`,`issuer certificate input is malformed`)}let r;try{r=e.responderCertificate??await de(t.certificates,t.responderId)??t.certificates?.[0]??e.issuerCertificate}catch{return z(`signature_invalid`,`OCSP responder certificate input is malformed`)}let i;try{i=await K(r)}catch{return z(`signature_invalid`,`OCSP responder certificate input is malformed`)}let a=await L(t,i);if(!a.ok)return z(a.code,a.message);let o;try{o=await fe(t.responderId,i)}catch{return z(`signature_invalid`,`OCSP responder certificate input is malformed`)}if(!o.ok)return o;if(!H(i,n)){let r=e.allowChainedResponderCertificate===!0;if(!r&&!pe(i,n))return z(`responder_chain_invalid`,`Delegated OCSP responder must be directly issued by issuer certificate`);if(!(await ae({leaf:i.der,intermediates:r?me(t.certificates,i,n):[],roots:[n.der]})).ok)return z(`responder_chain_invalid`,`OCSP responder certificate chain does not validate`);if(i.extendedKeyUsage===void 0||!i.extendedKeyUsage.includes(`ocspSigning`))return z(`ocsp_signing_missing`,`Delegated OCSP responder lacks ocspSigning EKU`)}let s=e.at??new Date,c=e.clockSkewMs??0;if(t.producedAt!==void 0&&t.producedAt.getTime()-c>s.getTime())return z(`stale_response`,`OCSP response producedAt is later than requested time`);for(let e of t.responses??[]){let r;try{r=await W(e.certId.hashAlgorithmOid,n,e.certId.serialNumberHex)}catch{return z(`signature_invalid`,`OCSP response CertID hash algorithm is unsupported`)}if(e.certId.issuerNameHashHex!==r.issuerNameHashHex||e.certId.issuerKeyHashHex!==r.issuerKeyHashHex)return z(`issuer_mismatch`,`OCSP response certId does not match issuer certificate`);if(e.thisUpdate.getTime()-c>s.getTime()||e.nextUpdate!==void 0&&e.nextUpdate.getTime()+c<s.getTime())return z(`stale_response`,`OCSP response is not valid at requested time`);if(t.producedAt!==void 0&&e.nextUpdate!==void 0&&t.producedAt.getTime()-c>e.nextUpdate.getTime())return z(`stale_response`,`OCSP response producedAt is later than nextUpdate`)}if(Ae(t.responses??[]))return z(`signature_invalid`,`OCSP response contains multiple status entries for the same certificate`);if(e.request!==void 0){let n;try{n=le(e.request)}catch{return z(`request_mismatch`,`OCSP request input is malformed`)}if(n.nonce!==void 0&&n.nonce!==t.nonce)return z(`nonce_mismatch`,`OCSP response nonce does not match request nonce`);let r=new Set(n.requests.map(e=>$(e))),i=new Set((t.responses??[]).map(e=>$(e.certId)));for(let e of t.responses??[])if(!r.has($(e.certId)))return z(`request_mismatch`,`OCSP response includes a certId not present in request`);for(let e of r)if(!i.has(e))return z(`request_mismatch`,`OCSP response does not cover every requested certId`)}return{ok:!0,value:t}}function R(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function z(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function B(e){if(typeof e==`string`)return I(e);if(e instanceof Uint8Array)return F(e);if(Q(e))return F(new Uint8Array(e.der));throw Error(`OCSP response input is malformed`)}function le(e){if(typeof e==`string`)return P(e);if(e instanceof Uint8Array)return N(e);if(Oe(e))return N(new Uint8Array(e.der));throw Error(`OCSP request input is malformed`)}function ue(e){let t=u(e);if(t.length<3||t.length>5)throw Error(`Malformed OCSP responseData`);let n=0;if(t[n]?.tag===160){let r=m(e,x(t[n],`version`)),i=x(r[0],`version`);if(r.length!==1||i.tag!==2)throw Error(`version must use INTEGER`);if(h(i.value,`OCSP response version`)!==0)throw Error(`Unsupported OCSP response version`);n+=1}let r=ye(e,x(t[n],`responderID`));n+=1;let i=x(t[n],`producedAt`),a=x(t[n+1],`responses`);if(a.tag!==48)throw Error(`responses must use SEQUENCE`);if(m(e,a).length===0)throw Error(`responses must not be empty`);let o=t[n+2];if(o!==void 0&&o.tag!==161||t.length!==n+2+(o===void 0?0:1))throw Error(`Malformed OCSP responseData`);let s=o===void 0?void 0:X(e,o),c=m(e,a).map(t=>ve(e,t));return ke(c),{responderId:r,producedAt:b(i),responses:c,...s===void 0?{}:{nonce:s}}}async function de(e,t){if(!(e===void 0||t===void 0)){for(let n of e)if(await V(t,n))return n}}async function fe(e,t){return e===void 0||await V(e,t)?{ok:!0}:e.type===`byName`?z(`responder_id_mismatch`,`OCSP responder certificate subject does not match responderID byName`):z(`responder_id_mismatch`,`OCSP responder certificate public key does not match responderID byKeyHash`)}async function V(e,t){return e.type===`byName`?Se(e.name,t.subject):C(await G(`SHA-1`,Z(t.subjectPublicKeyInfoDer)))===e.keyHashHex}function H(e,t){return e.serialNumberHex===t.serialNumberHex&&M(e.issuer,t.issuer)&&M(e.subject,t.subject)&&e.subjectPublicKeyInfoDer.length===t.subjectPublicKeyInfoDer.length&&e.subjectPublicKeyInfoDer.every((e,n)=>e===t.subjectPublicKeyInfoDer[n])}function pe(e,t){return!(!M(e.issuer,t.subject)||e.authorityKeyIdentifier!==void 0&&t.subjectKeyIdentifier!==void 0&&e.authorityKeyIdentifier!==t.subjectKeyIdentifier)}function me(e,t,n){if(e===void 0)return[];let r=[];for(let i of e)H(i,t)||H(i,n)||r.push(i.der);return r}async function U(e,t,n){let r=n===`SHA-1`?w.sha1:w.sha256,c=await W(r,t,e.serialNumberHex);return d([d([o(r),a()]),s(y(c.issuerNameHashHex)),s(y(c.issuerKeyHashHex)),i(y(c.serialNumberHex))])}async function W(e,t,n){let r=Ie(e);return{hashAlgorithmOid:e,hashAlgorithmName:k(e),issuerNameHashHex:C(await G(r,y(t.subject.derHex))),issuerKeyHashHex:C(await G(r,Z(t.subjectPublicKeyInfoDer))),serialNumberHex:n}}async function G(e,t){return new Uint8Array(await T().subtle.digest(e,S(t)))}async function he(e,t,r,i){return d([await U(e,t,i),ge(r),f(r.thisUpdate??new Date),...r.nextUpdate===void 0?[]:[n(0,f(r.nextUpdate))]])}function ge(e){switch(e.certStatus){case`good`:return p(128,new Uint8Array);case`unknown`:return p(130,new Uint8Array);case`revoked`:{let r=[f(e.revokedAt??e.thisUpdate??new Date)];return e.revocationReasonCode!==void 0&&r.push(n(0,p(10,Uint8Array.of(e.revocationReasonCode)))),p(161,t(r))}}}function K(e){return _e(e)?A(new Uint8Array(e.der)):j(e)}function _e(e){return typeof e!=`string`&&`subjectPublicKeyInfoDer`in e}function q(e){let t=l(e,{maxDepth:64});if(t.tag!==48)throw Error(`CertID must use SEQUENCE`);let n=m(e,t);if(n.length!==4)throw Error(`CertID must contain hashAlgorithm, issuerNameHash, issuerKeyHash, and serialNumber`);let r=x(n[0],`hashAlgorithm`);if(r.tag!==48)throw Error(`hashAlgorithm must use SEQUENCE`);let i=m(e,r);if(i.length<1||i.length>2)throw Error(`Malformed hashAlgorithm`);let a=g(x(i[0],`hashAlgorithm OID`).value);if(x(n[1],`issuerNameHash`).tag!==4)throw Error(`issuerNameHash must use OCTET STRING`);if(x(n[2],`issuerKeyHash`).tag!==4)throw Error(`issuerKeyHash must use OCTET STRING`);let o=x(n[3],`serialNumber`);if(o.tag!==2)throw Error(`serialNumber must use INTEGER`);return{hashAlgorithmOid:a,hashAlgorithmName:k(a),issuerNameHashHex:C(x(n[1],`issuerNameHash`).value),issuerKeyHashHex:C(x(n[2],`issuerKeyHash`).value),serialNumberHex:C(o.value)}}function ve(e,t){let n=m(e,t);if(n.length<3||n.length>5)throw Error(`Malformed OCSP SingleResponse`);let r=x(n[0],`certId`),i=x(n[1],`certStatus`),a=x(n[2],`thisUpdate`),o=3,s=n[o]?.tag===160?n[o]:void 0;s!==void 0&&(Ne(e,s),o+=1);let c=n[o];if(c!==void 0&&c.tag!==161||n.length!==o+(c===void 0?0:1))throw Error(`Malformed OCSP SingleResponse`);let l,u;if(i.tag===128){if(i.value.length!==0)throw Error(`OCSP good certStatus must be empty`);return{certId:q(e.slice(r.start-r.headerLength,r.end)),certStatus:`good`,thisUpdate:b(a),...s===void 0?{}:{nextUpdate:b(x(m(e,s)[0],`nextUpdate`))}}}if(i.tag===161){let t=m(e,i);if(t.length<1||t.length>2)throw Error(`Malformed OCSP revoked certStatus`);l=b(x(t[0],`revocationTime`));let n=t[1];if(n?.tag===160){let t=m(e,n),r=x(t[0],`revocationReason`);if(t.length!==1||r.tag!==10)throw Error(`revocationReason must use ENUMERATED`);u=h(r.value,`OCSP revocationReason`)}else if(n!==void 0)throw Error(`Malformed OCSP revoked certStatus`)}else if(i.tag!==130)throw Error(`Unsupported OCSP certStatus tag: ${String(i.tag)}`);else if(i.value.length!==0)throw Error(`OCSP unknown certStatus must be empty`);return{certId:q(e.slice(r.start-r.headerLength,r.end)),certStatus:i.tag===130?`unknown`:`revoked`,thisUpdate:b(a),...s===void 0?{}:{nextUpdate:b(x(m(e,s)[0],`nextUpdate`))},...l===void 0?{}:{revokedAt:l},...u===void 0?{}:{revocationReasonCode:u}}}function ye(e,t){switch(t.tag){case 130:if(t.value.length===0)throw Error(`ResponderID byKeyHash must not be empty`);return{type:`byKeyHash`,keyHashHex:C(t.value)};case 161:if(m(e,t).length!==1)throw Error(`ResponderID byName must wrap exactly one Name`);return{type:`byName`,name:be(e,x(m(e,t)[0],`ResponderID byName`))};default:throw Error(`Unsupported OCSP responderID tag: ${String(t.tag)}`)}}function be(e,t){if(t.tag!==48)throw Error(`ResponderID byName must use Name SEQUENCE`);let n=[],r=[],i={};for(let a of m(e,t)){let t=xe(e,a);n.push(t);for(let e of t.attributes)r.push(e),e.key!==void 0&&i[e.key]===void 0&&(i[e.key]=e.value)}return{derHex:C(e.slice(t.start-t.headerLength,t.end)),rdns:n,attributes:r,values:i}}function xe(e,t){let n=[],r={};for(let i of m(e,t)){let t=m(e,i),a=g(x(t[0],`name OID`).value),o=x(t[1],`name value`),s=Te(a),c=_(o.tag,o.value),l=s===void 0?{oid:a,valueTag:o.tag,value:c}:{oid:a,key:s,valueTag:o.tag,value:c};n.push(l),s!==void 0&&r[s]===void 0&&(r[s]=c)}return{derHex:C(e.slice(t.start-t.headerLength,t.end)),attributes:n,values:r}}function Se(e,t){if(e.rdns.length!==t.rdns.length)return!1;for(let n=0;n<e.rdns.length;n+=1){let r=e.rdns[n],i=t.rdns[n];if(r===void 0||i===void 0||!Ce(r,i))return!1}return!0}function Ce(e,t){if(e.attributes.length!==t.attributes.length)return!1;let n=Array(t.attributes.length).fill(!1);for(let r of e.attributes){let e=!1;for(let i=0;i<t.attributes.length;i+=1){let a=t.attributes[i];if(!(a===void 0||n[i])&&we(r,a)){n[i]=!0,e=!0;break}}if(!e)return!1}return!0}function we(e,t){if(e.oid!==t.oid)return!1;if(J(e.valueTag)&&J(t.valueTag)){let n=Y(e.value),r=Y(t.value);return n===void 0||r===void 0?!1:n===r}return e.valueTag===t.valueTag&&e.value===t.value}function J(e){return e===12||e===19}function Y(e){let t=e.normalize(`NFKC`);if(!/[^\P{Cc}\t\n\r]/u.test(t))return t.toLowerCase().trim().replace(/\s+/gu,` `)}function Te(e){switch(e){case w.commonName:return`commonName`;case w.surname:return`surname`;case w.serialNumber:return`serialNumber`;case w.countryName:return`country`;case w.localityName:return`locality`;case w.stateOrProvinceName:return`state`;case w.streetAddress:return`street`;case w.organizationName:return`organization`;case w.organizationalUnitName:return`organizationalUnit`;case w.title:return`title`;case w.givenName:return`givenName`;case w.emailAddress:return`emailAddress`;default:return}}function X(e,t){let n=m(e,t),r=x(n[0],`extensions`);if(n.length!==1||r.tag!==48)throw Error(`Malformed OCSP extensions`);let i=new Set,a;for(let t of m(e,r)){let n=m(e,t);if(n.length<2||n.length>3||n.length===3&&n[1]?.tag!==1)throw Error(`Malformed OCSP extension`);let r=g(x(n[0],`extension OID`).value);if(i.has(r))throw Error(`Duplicate OCSP extension OID: ${r}`);i.add(r);let o=x(n[n.length-1],`extnValue`);if(o.tag!==4)throw Error(`OCSP extension value must use OCTET STRING`);if(r!==w.ocspNonce)continue;let s=l(o.value,{maxDepth:64});if(s.tag!==4)throw Error(`OCSP nonce extension value must use OCTET STRING`);a=C(s.value)}return a}function Ee(e,t){let n=[],r=t.start;for(;r<t.end;){let t=c(e,r);n.push(A(e.slice(r,t.end))),r=t.end}return n}function Z(e){let t=x(m(e,c(e))[1],`subjectPublicKey BIT STRING`);if(t.tag!==3)throw Error(`SPKI missing subjectPublicKey BIT STRING`);return t.value.slice(1)}function De(e){switch(e){case 0:return`successful`;case 1:return`malformedRequest`;case 2:return`internalError`;case 3:return`tryLater`;case 5:return`sigRequired`;case 6:return`unauthorized`;default:throw Error(`Unsupported OCSP responseStatus value: ${String(e)}`)}}function Oe(e){return`der`in e&&e.der instanceof Uint8Array}function Q(e){return`der`in e&&e.der instanceof Uint8Array}function ke(e){let t=new Set;for(let n of e){let e=$(n.certId);if(t.has(e))throw Error(`Duplicate OCSP response CertID`);t.add(e)}}function Ae(e){let t=new Set;for(let n of e){let e=Fe(n.certId.serialNumberHex);if(t.has(e))return!0;t.add(e)}return!1}function je(e,t){let n=m(e,t),r=x(n[0],`requestorName`);if(n.length!==1||(r.tag&192)!=128)throw Error(`requestorName must wrap exactly one GeneralName`)}function Me(e,t){let n=m(e,t),r=x(n[0],`optionalSignature`);if(n.length!==1||r.tag!==48)throw Error(`optionalSignature must wrap exactly one Signature`);let i=m(e,r);if(i.length<2||i.length>3||i[0]?.tag!==48||i[2]!==void 0&&i[2]?.tag!==160)throw Error(`Malformed optionalSignature`);let a=x(i[0],`signatureAlgorithm`),o=x(i[1],`signature`),s=i[2];if(Pe(e,a,`optionalSignature algorithm`),v(o),s!==void 0){let t=m(e,s);if(t.length!==1||t[0]?.tag!==48)throw Error(`optionalSignature certs must use SEQUENCE OF Certificate`)}}function Ne(e,t){let n=m(e,t),r=x(n[0],`nextUpdate`);if(n.length!==1||r.tag!==23&&r.tag!==24)throw Error(`nextUpdate must wrap exactly one time value`)}function Pe(e,t,n){let r=m(e,t);if(t.tag!==48||r.length<1||r.length>2||r[0]?.tag!==6)throw Error(`${n} must use AlgorithmIdentifier SEQUENCE`);g(x(r[0],`${n} OID`).value)}function Fe(e){return e.toLowerCase()}function Ie(e){switch(e){case w.sha1:return`SHA-1`;case w.sha256:return`SHA-256`;default:throw Error(`Unsupported OCSP hash algorithm OID: ${e}`)}}function $(e){return[e.hashAlgorithmOid,e.issuerNameHashHex,e.issuerKeyHashHex,e.serialNumberHex].join(`:`)}export{oe as createOcspRequest,se as createOcspResponse,N as parseOcspRequestDer,P as parseOcspRequestPem,F as parseOcspResponseDer,I as parseOcspResponsePem,ce as validateOcspResponse,L as verifyOcspResponse};
2
+ //# sourceMappingURL=ocsp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocsp.js","names":[],"sources":["../../src/revocation/ocsp.ts"],"sourcesContent":["/**\n * Full OCSP lifecycle: build requests, create/parse/verify/validate responses.\n *\n * Supports SHA-1 and SHA-256 cert-ID hashing, nonce replay protection,\n * delegated responder certificate validation (direct and chain-based),\n * and embedded responder certificate discovery.\n *\n * @module\n */\n\nimport {\n\tchildrenOf,\n\tdecodeNonNegativeIntegerNumber,\n\tdecodeObjectIdentifier,\n\tdecodeString,\n\textractBitStringValue,\n\thexToBytes,\n\tparseTime,\n\trequireElement,\n\ttoArrayBuffer,\n\ttoHex,\n} from '#micro509/internal/asn1/asn1.ts';\nimport type { DerElement } from '#micro509/internal/asn1/der.ts';\nimport {\n\tbitString,\n\tconcatBytes,\n\tDEFAULT_MAX_DER_DEPTH,\n\texplicitContext,\n\timplicitPrimitiveContext,\n\tinteger,\n\tnullValue,\n\tobjectIdentifier,\n\toctetString,\n\treadElement,\n\treadRootElement,\n\treadSequenceChildren,\n\tsequence,\n\ttime,\n\ttlv,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport {\n\tdescribeHashAlgorithm,\n\tdescribeSignatureAlgorithm,\n} from '#micro509/internal/crypto/algorithm-names.ts';\nimport { verifySignedDataDetailed } from '#micro509/internal/crypto/sig-verify.ts';\nimport {\n\tencodeAlgorithmIdentifier,\n\tgetSignatureAlgorithm,\n\tsignBytes,\n} from '#micro509/internal/crypto/signing.ts';\nimport { getCrypto } from '#micro509/internal/crypto/webcrypto.ts';\nimport { base64Encode } from '#micro509/internal/shared/base64.ts';\nimport { compareDistinguishedNames } from '#micro509/internal/shared/dn.ts';\nimport { pemDecode, pemEncode } from '#micro509/pem/pem.ts';\nimport type { ErrorResult, Micro509Error } from '#micro509/result/result.ts';\nimport { verifyCertificateChain } from '#micro509/verify/verify.ts';\nimport type {\n\tParsedCertificate,\n\tParsedName,\n\tParsedNameAttribute,\n\tParsedRelativeDistinguishedName,\n} from '#micro509/x509/parse.ts';\nimport { parseCertificateDer, parseCertificateFromSource } from '#micro509/x509/parse.ts';\n\n/** Hash algorithm used to compute OCSP CertID fields. SHA-1 is the RFC 6960 default. */\nexport type OcspHashAlgorithm = 'SHA-1' | 'SHA-256';\n/** PEM string, DER bytes, or already-parsed certificate. */\nexport type OcspCertificateSource = string | Uint8Array | ParsedCertificate;\n/** PEM string, DER bytes, or already-parsed OCSP request. */\nexport type OcspRequestSource = string | Uint8Array | ParsedOcspRequest;\n\n/**\n * One certificate whose status to query in an OCSP request.\n * Used as an element of {@linkcode CreateOcspRequestInput.requests}.\n */\nexport interface CreateOcspRequestItemInput {\n\t/** Certificate whose revocation status is being queried. */\n\treadonly certificate: OcspCertificateSource;\n\t/** Issuer of `certificate` — needed to compute the CertID hash. */\n\treadonly issuerCertificate: OcspCertificateSource;\n}\n\n/**\n * Input for {@linkcode createOcspRequest}.\n */\nexport interface CreateOcspRequestInput {\n\t/** One or more certificates to query (batched into a single OCSP request). */\n\treadonly requests: readonly CreateOcspRequestItemInput[];\n\t/** Hash algorithm for CertID computation. Defaults to `'SHA-1'`. */\n\treadonly hashAlgorithm?: OcspHashAlgorithm;\n\t/** Random nonce for replay protection. Omit to skip the nonce extension. */\n\treadonly nonce?: Uint8Array;\n}\n\n/**\n * Encoded OCSP request in multiple serialisation formats, returned by {@linkcode createOcspRequest}.\n */\nexport interface OcspRequestMaterial {\n\t/** Raw DER bytes. */\n\treadonly der: Uint8Array;\n\t/** PEM-encoded request (`-----BEGIN OCSP REQUEST-----`). */\n\treadonly pem: string;\n\t/** Base64-encoded DER (no PEM armour). */\n\treadonly base64: string;\n}\n\n/**\n * Decoded OCSP CertID — identifies a certificate by hashed issuer name,\n * hashed issuer key, and serial number.\n */\nexport interface ParsedOcspCertId {\n\t/** OID of the hash algorithm used for the name and key hashes. */\n\treadonly hashAlgorithmOid: string;\n\t/** Human-readable hash algorithm name (e.g. `\"SHA-256\"`). */\n\treadonly hashAlgorithmName: string;\n\t/** Hex-encoded hash of the issuer's distinguished name DER. */\n\treadonly issuerNameHashHex: string;\n\t/** Hex-encoded hash of the issuer's SubjectPublicKey BIT STRING content. */\n\treadonly issuerKeyHashHex: string;\n\t/** Hex-encoded serial number of the certificate. */\n\treadonly serialNumberHex: string;\n}\n\n/**\n * Decoded OCSP request, returned by {@linkcode parseOcspRequestDer} / {@linkcode parseOcspRequestPem}.\n */\nexport interface ParsedOcspRequest {\n\t/** Original DER bytes when this object came from {@linkcode parseOcspRequestDer} or PEM parsing. */\n\treadonly der?: Uint8Array;\n\t/** CertIDs of the certificates being queried. */\n\treadonly requests: readonly ParsedOcspCertId[];\n\t/** Hex-encoded nonce extension value, if present. */\n\treadonly nonce?: string;\n}\n\n/** RFC 6960 certificate status reported by the responder for a single CertID. */\nexport type OcspCertStatus = 'good' | 'revoked' | 'unknown';\n/** RFC 6960 overall response status — anything other than `'successful'` means the response body is absent or unusable. */\nexport type OcspResponseStatus =\n\t| 'successful'\n\t| 'malformedRequest'\n\t| 'internalError'\n\t| 'tryLater'\n\t| 'sigRequired'\n\t| 'unauthorized';\n\n/**\n * Status of one certificate inside an OCSP BasicResponse.\n */\nexport interface ParsedOcspSingleResponse {\n\t/** Which certificate this status applies to. */\n\treadonly certId: ParsedOcspCertId;\n\t/** Responder's verdict: `good`, `revoked`, or `unknown`. */\n\treadonly certStatus: OcspCertStatus;\n\t/** Start of the validity window for this status assertion. */\n\treadonly thisUpdate: Date;\n\t/** End of the validity window. Absent if the responder does not commit to a schedule. */\n\treadonly nextUpdate?: Date;\n\t/** When the certificate was revoked (only for `certStatus === 'revoked'`). */\n\treadonly revokedAt?: Date;\n\t/** CRLReason integer (only for `certStatus === 'revoked'`). */\n\treadonly revocationReasonCode?: number;\n}\n\n/**\n * How the OCSP responder identifies itself — either by distinguished name or\n * by SHA-1 hash of its public key.\n */\nexport type ParsedOcspResponderId =\n\t| {\n\t\t\t/** Responder identified by its certificate subject name. */\n\t\t\treadonly type: 'byName';\n\t\t\t/** Parsed distinguished name of the responder. */\n\t\t\treadonly name: ParsedName;\n\t }\n\t| {\n\t\t\t/** Responder identified by public-key hash. */\n\t\t\treadonly type: 'byKeyHash';\n\t\t\t/** Hex-encoded SHA-1 hash of the responder's SubjectPublicKey content. */\n\t\t\treadonly keyHashHex: string;\n\t };\n\n/**\n * Decoded OCSP response, returned by {@linkcode parseOcspResponseDer} / {@linkcode parseOcspResponsePem}.\n *\n * When `responseStatus` is not `'successful'`, most fields are absent.\n */\nexport interface ParsedOcspResponse {\n\t/** Original DER bytes when this object came from {@linkcode parseOcspResponseDer} or PEM parsing. */\n\treadonly der?: Uint8Array;\n\t/** Overall response status. Only `'successful'` carries a BasicOCSPResponse body. */\n\treadonly responseStatus: OcspResponseStatus;\n\t/** OID of the response type (normally `id-pkix-ocsp-basic`). */\n\treadonly responseTypeOid?: string;\n\t/** DER-encoded ResponseData — the signed payload for signature verification. */\n\treadonly responseDataDer?: Uint8Array;\n\t/** How the responder identifies itself. */\n\treadonly responderId?: ParsedOcspResponderId;\n\t/** OID of the algorithm used to sign this response. */\n\treadonly signatureAlgorithmOid?: string;\n\t/** Human-readable signature algorithm name. */\n\treadonly signatureAlgorithmName?: string;\n\t/** Raw signature bytes. */\n\treadonly signatureValue?: Uint8Array;\n\t/** Timestamp when the responder produced this response. */\n\treadonly producedAt?: Date;\n\t/** Per-certificate status entries. */\n\treadonly responses?: readonly ParsedOcspSingleResponse[];\n\t/** Hex-encoded nonce, if the response echoed one. */\n\treadonly nonce?: string;\n\t/** Certificates embedded in the response (typically the responder's chain). */\n\treadonly certificates?: readonly ParsedCertificate[];\n}\n\n/**\n * One certificate's status entry for {@linkcode CreateOcspResponseInput.responses}.\n * Extends {@linkcode CreateOcspRequestItemInput} with status and timing fields.\n */\nexport interface CreateOcspSingleResponseInput extends CreateOcspRequestItemInput {\n\t/** Status to assert for this certificate. */\n\treadonly certStatus: OcspCertStatus;\n\t/** Start of the validity window for this status assertion. Defaults to `new Date()`. */\n\treadonly thisUpdate?: Date;\n\t/** End of the validity window. Omit for open-ended assertions. */\n\treadonly nextUpdate?: Date;\n\t/** Revocation time (required when `certStatus` is `'revoked'`). Defaults to `thisUpdate`. */\n\treadonly revokedAt?: Date;\n\t/** CRLReason integer code (only meaningful when `certStatus` is `'revoked'`). */\n\treadonly revocationReasonCode?: number;\n}\n\n/**\n * Input for {@linkcode createOcspResponse}.\n */\nexport interface CreateOcspResponseInput {\n\t/** Private key used to sign the response. Algorithm is inferred from the key. */\n\treadonly signerPrivateKey: CryptoKey;\n\t/** Certificate of the OCSP responder — used to build the responder ID (by key hash). */\n\treadonly signerCertificate: OcspCertificateSource;\n\t/** Per-certificate status entries to include in the BasicOCSPResponse. */\n\treadonly responses: readonly CreateOcspSingleResponseInput[];\n\t/** Timestamp for the `producedAt` field. Defaults to `new Date()`. */\n\treadonly producedAt?: Date;\n\t/** Nonce to echo back for replay protection. */\n\treadonly nonce?: Uint8Array;\n\t/** Hash algorithm for CertID computation. Defaults to `'SHA-1'`. */\n\treadonly hashAlgorithm?: OcspHashAlgorithm;\n\t/** Extra certificates to embed in the response (e.g. the responder's issuer chain). */\n\treadonly includedCertificates?: readonly OcspCertificateSource[];\n}\n\n/**\n * Encoded OCSP response in multiple serialisation formats, returned by {@linkcode createOcspResponse}.\n */\nexport interface OcspResponseMaterial {\n\t/** Raw DER bytes. */\n\treadonly der: Uint8Array;\n\t/** PEM-encoded response (`-----BEGIN OCSP RESPONSE-----`). */\n\treadonly pem: string;\n\t/** Base64-encoded DER (no PEM armour). */\n\treadonly base64: string;\n}\n\n/** Failure detail when OCSP response signature verification fails. */\nexport interface VerifyOcspResponseFailure extends Micro509Error<'signature_invalid'> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/**\n * Result of {@linkcode verifyOcspResponse}.\n *\n * On success, `value` is the parsed response whose signature has been verified.\n */\nexport type VerifyOcspResponseResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\t/** Parsed response with a verified signature. */\n\t\t\treadonly value: ParsedOcspResponse;\n\t }\n\t| ErrorResult<'signature_invalid', Record<never, never>, VerifyOcspResponseFailure>;\n\n/**\n * Input for {@linkcode validateOcspResponse}.\n */\nexport interface ValidateOcspResponseInput {\n\t/** The OCSP response to validate. */\n\treadonly response: string | Uint8Array | ParsedOcspResponse;\n\t/** Certificate of the CA that issued the target certificate. */\n\treadonly issuerCertificate: OcspCertificateSource;\n\t/** Original request — enables nonce and request-coverage checks. */\n\treadonly request?: OcspRequestSource;\n\t/** Explicit responder certificate — overrides embedded certificate discovery. */\n\treadonly responderCertificate?: OcspCertificateSource;\n\t/** When `true`, allows delegated responder chain validation beyond direct issuance. */\n\treadonly allowChainedResponderCertificate?: boolean;\n\t/** Evaluation time for freshness checks. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** Clock-skew tolerance in milliseconds for `thisUpdate`/`nextUpdate`/`producedAt`. */\n\treadonly clockSkewMs?: number;\n}\n\n/**\n * Failure detail for {@linkcode validateOcspResponse}.\n *\n * Possible codes: `response_status_invalid`, `signature_invalid`,\n * `responder_id_mismatch`, `nonce_mismatch`, `request_mismatch`,\n * `issuer_mismatch`, `responder_chain_invalid`, `ocsp_signing_missing`,\n * `stale_response`.\n */\nexport interface ValidateOcspResponseFailure\n\textends Micro509Error<\n\t\t| 'response_status_invalid'\n\t\t| 'signature_invalid'\n\t\t| 'responder_id_mismatch'\n\t\t| 'nonce_mismatch'\n\t\t| 'request_mismatch'\n\t\t| 'issuer_mismatch'\n\t\t| 'responder_chain_invalid'\n\t\t| 'ocsp_signing_missing'\n\t\t| 'stale_response'\n\t> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/**\n * Result of {@linkcode validateOcspResponse}.\n *\n * On success, the response has passed status, signature, responder binding,\n * freshness, nonce, and request-coverage checks.\n */\nexport type ValidateOcspResponseResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\t/** Fully validated OCSP response. */\n\t\t\treadonly value: ParsedOcspResponse;\n\t }\n\t| ErrorResult<\n\t\t\t| 'response_status_invalid'\n\t\t\t| 'signature_invalid'\n\t\t\t| 'responder_id_mismatch'\n\t\t\t| 'nonce_mismatch'\n\t\t\t| 'request_mismatch'\n\t\t\t| 'issuer_mismatch'\n\t\t\t| 'responder_chain_invalid'\n\t\t\t| 'ocsp_signing_missing'\n\t\t\t| 'stale_response',\n\t\t\tRecord<never, never>,\n\t\t\tValidateOcspResponseFailure\n\t >;\n\n/**\n * Builds a DER-encoded OCSP request containing one or more CertID entries\n * and an optional nonce extension.\n *\n * @example\n * ```ts\n * import { createOcspRequest } from 'micro509';\n *\n * const req = await createOcspRequest({\n * requests: [{ certificate: leafPem, issuerCertificate: caPem }],\n * hashAlgorithm: 'SHA-256',\n * nonce: crypto.getRandomValues(new Uint8Array(16)),\n * });\n * // POST req.der to the OCSP responder URI\n * ```\n */\nexport async function createOcspRequest(\n\tinput: CreateOcspRequestInput,\n): Promise<OcspRequestMaterial> {\n\tconst hashAlgorithm = input.hashAlgorithm ?? 'SHA-1';\n\tconst requestEntries: Uint8Array[] = [];\n\tfor (const request of input.requests) {\n\t\tconst certificate = await normalizeCertificate(request.certificate);\n\t\tconst issuer = await normalizeCertificate(request.issuerCertificate);\n\t\trequestEntries.push(sequence([await encodeOcspCertId(certificate, issuer, hashAlgorithm)]));\n\t}\n\tconst tbsRequestFields: Uint8Array[] = [sequence(requestEntries)];\n\tif (input.nonce !== undefined) {\n\t\ttbsRequestFields.push(\n\t\t\texplicitContext(\n\t\t\t\t2,\n\t\t\t\tsequence([\n\t\t\t\t\tsequence([objectIdentifier(OIDS.ocspNonce), octetString(octetString(input.nonce))]),\n\t\t\t\t]),\n\t\t\t),\n\t\t);\n\t}\n\tconst der = sequence([sequence(tbsRequestFields)]);\n\treturn {\n\t\tder,\n\t\tpem: pemEncode('OCSP REQUEST', der),\n\t\tbase64: base64Encode(der),\n\t};\n}\n\n/** Decodes a DER-encoded OCSP request into a structured {@linkcode ParsedOcspRequest}. */\nexport function parseOcspRequestDer(der: Uint8Array): ParsedOcspRequest {\n\tconst top = readSequenceChildren(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (top.length < 1 || top.length > 2) {\n\t\tthrow new Error('Malformed OCSP request');\n\t}\n\tconst tbsRequest = requireElement(top[0], 'tbsRequest');\n\tconst optionalSignature = top[1];\n\tif (optionalSignature !== undefined && optionalSignature.tag !== 0xa0) {\n\t\tthrow new Error('Malformed OCSP request');\n\t}\n\tif (optionalSignature !== undefined) {\n\t\tvalidateOcspOptionalSignature(der, optionalSignature);\n\t}\n\tconst tbsChildren = childrenOf(der, tbsRequest);\n\tlet cursor = 0;\n\tif (tbsChildren[cursor]?.tag === 0xa0) {\n\t\tconst versionWrapper = requireElement(tbsChildren[cursor], 'version');\n\t\tconst versionFields = childrenOf(der, versionWrapper);\n\t\tconst versionElement = requireElement(versionFields[0], 'version');\n\t\tif (versionFields.length !== 1 || versionElement.tag !== 0x02) {\n\t\t\tthrow new Error('version must use INTEGER');\n\t\t}\n\t\tif (decodeNonNegativeIntegerNumber(versionElement.value, 'OCSP request version') !== 0) {\n\t\t\tthrow new Error('Unsupported OCSP request version');\n\t\t}\n\t\tcursor += 1;\n\t}\n\tconst requestorName = tbsChildren[cursor];\n\tif (requestorName?.tag === 0xa1) {\n\t\tvalidateOcspRequestorName(der, requestorName);\n\t\tcursor += 1;\n\t}\n\tconst requestList = requireElement(tbsChildren[cursor], 'requestList');\n\tif (requestList.tag !== 0x30) {\n\t\tthrow new Error('requestList must use SEQUENCE');\n\t}\n\tif (childrenOf(der, requestList).length === 0) {\n\t\tthrow new Error('requestList must not be empty');\n\t}\n\tconst requests = childrenOf(der, requestList).map((request) => {\n\t\tconst requestChildren = childrenOf(der, request);\n\t\tif (requestChildren.length < 1 || requestChildren.length > 2) {\n\t\t\tthrow new Error('Malformed OCSP request entry');\n\t\t}\n\t\tif (requestChildren[1] !== undefined && requestChildren[1].tag !== 0xa0) {\n\t\t\tthrow new Error('Malformed OCSP request entry');\n\t\t}\n\t\tconst certId = requireElement(requestChildren[0], 'reqCert');\n\t\treturn parseOcspCertId(der.slice(certId.start - certId.headerLength, certId.end));\n\t});\n\tcursor += 1;\n\tconst extensions = tbsChildren[cursor];\n\tif (extensions !== undefined && extensions.tag !== 0xa2) {\n\t\tthrow new Error('Malformed OCSP request');\n\t}\n\tif (tbsChildren.length !== cursor + (extensions === undefined ? 0 : 1)) {\n\t\tthrow new Error('Malformed OCSP request');\n\t}\n\tconst nonce =\n\t\textensions === undefined ? undefined : parseOcspNonceFromExtensions(der, extensions);\n\treturn {\n\t\tder: new Uint8Array(der),\n\t\trequests,\n\t\t...(nonce === undefined ? {} : { nonce }),\n\t};\n}\n\n/** Decodes a PEM-encoded OCSP request (`-----BEGIN OCSP REQUEST-----`). */\nexport function parseOcspRequestPem(pem: string): ParsedOcspRequest {\n\treturn parseOcspRequestDer(pemDecode('OCSP REQUEST', pem));\n}\n\n/** Decodes a DER-encoded OCSP response into a structured {@linkcode ParsedOcspResponse}. Does not verify the signature. */\nexport function parseOcspResponseDer(der: Uint8Array): ParsedOcspResponse {\n\tconst top = readSequenceChildren(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (top.length < 1 || top.length > 2) {\n\t\tthrow new Error('Malformed OCSP response');\n\t}\n\tconst statusElement = requireElement(top[0], 'responseStatus');\n\tif (statusElement.tag !== 0x0a) {\n\t\tthrow new Error('responseStatus must use ENUMERATED');\n\t}\n\tconst responseStatus = ocspResponseStatusFromCode(\n\t\tdecodeNonNegativeIntegerNumber(statusElement.value, 'OCSP responseStatus'),\n\t);\n\tconst responseBytes = top[1];\n\tif (responseBytes === undefined) {\n\t\treturn { der: new Uint8Array(der), responseStatus };\n\t}\n\tif (responseBytes.tag !== 0xa0) {\n\t\tthrow new Error('Malformed OCSP response');\n\t}\n\tconst responseBytesWrapper = childrenOf(der, responseBytes);\n\tconst bytesSequence = requireElement(responseBytesWrapper[0], 'responseBytes');\n\tif (responseBytesWrapper.length !== 1 || bytesSequence.tag !== 0x30) {\n\t\tthrow new Error('Malformed OCSP response');\n\t}\n\tconst responseBytesChildren = childrenOf(der, bytesSequence);\n\tif (responseBytesChildren.length !== 2) {\n\t\tthrow new Error('responseBytes must contain responseType and response');\n\t}\n\tconst responseType = requireElement(responseBytesChildren[0], 'responseType');\n\tconst response = requireElement(responseBytesChildren[1], 'response');\n\tif (response.tag !== 0x04) {\n\t\tthrow new Error('response must use OCTET STRING');\n\t}\n\tconst responseTypeOid = decodeObjectIdentifier(responseType.value);\n\tif (responseTypeOid !== OIDS.ocspBasicResponse) {\n\t\treturn { der: new Uint8Array(der), responseStatus, responseTypeOid };\n\t}\n\tconst basicResponse = response.value;\n\tconst basicChildren = readSequenceChildren(basicResponse);\n\tif (basicChildren.length < 3 || basicChildren.length > 4) {\n\t\tthrow new Error('Malformed BasicOCSPResponse');\n\t}\n\tconst responseData = requireElement(basicChildren[0], 'responseData');\n\tconst signatureAlgorithm = requireElement(basicChildren[1], 'signatureAlgorithm');\n\tconst signatureValue = requireElement(basicChildren[2], 'signatureValue');\n\tconst certificatesElement = basicChildren[3];\n\tif (certificatesElement !== undefined && certificatesElement.tag !== 0xa0) {\n\t\tthrow new Error('Malformed BasicOCSPResponse');\n\t}\n\tconst signatureAlgorithmChildren = childrenOf(basicResponse, signatureAlgorithm);\n\tconst signatureAlgorithmOid = decodeObjectIdentifier(\n\t\trequireElement(signatureAlgorithmChildren[0], 'signatureAlgorithm OID').value,\n\t);\n\tconst signatureAlgorithmParameters = signatureAlgorithmChildren[1];\n\tconst responseDataDer = basicResponse.slice(\n\t\tresponseData.start - responseData.headerLength,\n\t\tresponseData.end,\n\t);\n\tconst signedResponseData = parseSignedOcspResponseData(responseDataDer);\n\treturn {\n\t\tder: new Uint8Array(der),\n\t\tresponseStatus,\n\t\tresponseTypeOid,\n\t\tresponseDataDer,\n\t\tresponderId: signedResponseData.responderId,\n\t\tsignatureAlgorithmOid,\n\t\tsignatureAlgorithmName: describeSignatureAlgorithm(\n\t\t\tsignatureAlgorithmOid,\n\t\t\tsignatureAlgorithmParameters === undefined\n\t\t\t\t? undefined\n\t\t\t\t: basicResponse.slice(\n\t\t\t\t\t\tsignatureAlgorithmParameters.start - signatureAlgorithmParameters.headerLength,\n\t\t\t\t\t\tsignatureAlgorithmParameters.end,\n\t\t\t\t\t),\n\t\t),\n\t\tsignatureValue: extractBitStringValue(signatureValue),\n\t\tproducedAt: signedResponseData.producedAt,\n\t\tresponses: signedResponseData.responses,\n\t\t...(signedResponseData.nonce === undefined ? {} : { nonce: signedResponseData.nonce }),\n\t\t...(certificatesElement?.tag === 0xa0\n\t\t\t? {\n\t\t\t\t\tcertificates: parseEmbeddedCertificates(basicResponse, certificatesElement),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Decodes a PEM-encoded OCSP response (`-----BEGIN OCSP RESPONSE-----`).\n *\n * @example\n * ```ts\n * import { parseOcspResponsePem } from 'micro509';\n *\n * const resp = parseOcspResponsePem(pemString);\n * if (resp.responseStatus === 'successful') {\n * for (const entry of resp.responses ?? []) {\n * console.log(entry.certId.serialNumberHex, entry.certStatus);\n * }\n * }\n * ```\n */\nexport function parseOcspResponsePem(pem: string): ParsedOcspResponse {\n\treturn parseOcspResponseDer(pemDecode('OCSP RESPONSE', pem));\n}\n\n/**\n * Signs and encodes an OCSP BasicResponse with a `successful` status.\n *\n * The responder is identified by key hash (SHA-1 of the signer's SubjectPublicKey).\n * Use `includedCertificates` to embed the responder's chain for relying parties.\n *\n * @example\n * ```ts\n * import { createOcspResponse } from 'micro509';\n *\n * const resp = await createOcspResponse({\n * signerPrivateKey: responderPrivateKey,\n * signerCertificate: responderCertPem,\n * responses: [\n * {\n * certificate: leafPem,\n * issuerCertificate: caPem,\n * certStatus: 'good',\n * thisUpdate: new Date('2025-01-01'),\n * nextUpdate: new Date('2025-01-08'),\n * },\n * ],\n * nonce: requestNonce,\n * });\n * // resp.der, resp.pem, resp.base64\n * ```\n */\nexport async function createOcspResponse(\n\tinput: CreateOcspResponseInput,\n): Promise<OcspResponseMaterial> {\n\tconst signerCertificate = await normalizeCertificate(input.signerCertificate);\n\tconst signatureAlgorithm = getSignatureAlgorithm(input.signerPrivateKey);\n\tconst producedAt = input.producedAt ?? new Date();\n\tconst hashAlgorithm = input.hashAlgorithm ?? 'SHA-1';\n\tconst responses: Uint8Array[] = [];\n\tfor (const response of input.responses) {\n\t\tconst certificate = await normalizeCertificate(response.certificate);\n\t\tconst issuer = await normalizeCertificate(response.issuerCertificate);\n\t\tresponses.push(await encodeSingleResponse(certificate, issuer, response, hashAlgorithm));\n\t}\n\tconst responderKeyHash = await digestBytes(\n\t\t'SHA-1',\n\t\textractSubjectPublicKeyBytes(signerCertificate.subjectPublicKeyInfoDer),\n\t);\n\tconst responseDataFields: Uint8Array[] = [\n\t\timplicitPrimitiveContext(2, responderKeyHash),\n\t\ttime(producedAt),\n\t\tsequence(responses),\n\t];\n\tif (input.nonce !== undefined) {\n\t\tresponseDataFields.push(\n\t\t\texplicitContext(\n\t\t\t\t1,\n\t\t\t\tsequence([\n\t\t\t\t\tsequence([objectIdentifier(OIDS.ocspNonce), octetString(octetString(input.nonce))]),\n\t\t\t\t]),\n\t\t\t),\n\t\t);\n\t}\n\tconst responseData = sequence(responseDataFields);\n\tconst signature = await signBytes(input.signerPrivateKey, signatureAlgorithm, responseData);\n\tconst includedCertificates =\n\t\tinput.includedCertificates === undefined\n\t\t\t? []\n\t\t\t: await Promise.all(input.includedCertificates.map(normalizeCertificate));\n\tconst basicResponseFields: Uint8Array[] = [\n\t\tresponseData,\n\t\tencodeAlgorithmIdentifier(signatureAlgorithm),\n\t\tbitString(signature),\n\t];\n\tif (includedCertificates.length > 0) {\n\t\tbasicResponseFields.push(\n\t\t\texplicitContext(0, concatBytes(includedCertificates.map((certificate) => certificate.der))),\n\t\t);\n\t}\n\tconst basicResponse = sequence(basicResponseFields);\n\tconst der = sequence([\n\t\ttlv(0x0a, Uint8Array.of(0x00)),\n\t\texplicitContext(\n\t\t\t0,\n\t\t\tsequence([objectIdentifier(OIDS.ocspBasicResponse), octetString(basicResponse)]),\n\t\t),\n\t]);\n\treturn {\n\t\tder,\n\t\tpem: pemEncode('OCSP RESPONSE', der),\n\t\tbase64: base64Encode(der),\n\t};\n}\n\n/**\n * Verifies the OCSP response signature against the given signer certificate.\n *\n * Does **not** check responder binding, freshness, or nonce — use\n * {@linkcode validateOcspResponse} for full validation.\n */\nexport async function verifyOcspResponse(\n\tresponse: string | Uint8Array | ParsedOcspResponse,\n\tsignerCertificate: OcspCertificateSource,\n): Promise<VerifyOcspResponseResult> {\n\tlet parsed: ParsedOcspResponse;\n\ttry {\n\t\tparsed = normalizeOcspResponse(response);\n\t} catch {\n\t\treturn verifyOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP response signed content is malformed',\n\t\t);\n\t}\n\tif (\n\t\tparsed.responseDataDer === undefined ||\n\t\tparsed.signatureAlgorithmOid === undefined ||\n\t\tparsed.signatureValue === undefined\n\t) {\n\t\treturn verifyOcspResponseFailureResult('signature_invalid', 'OCSP response is not signed');\n\t}\n\tlet signer: ParsedCertificate;\n\ttry {\n\t\tsigner = await normalizeCertificate(signerCertificate);\n\t} catch {\n\t\treturn verifyOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP signer certificate input is malformed',\n\t\t);\n\t}\n\tlet verifiedResult: Awaited<ReturnType<typeof verifySignedDataDetailed>>;\n\ttry {\n\t\tverifiedResult = await verifySignedDataDetailed(\n\t\t\tparsed.signatureAlgorithmOid,\n\t\t\tundefined,\n\t\t\tsigner.publicKeyAlgorithmOid,\n\t\t\tsigner.publicKeyParametersOid,\n\t\t\tsigner.subjectPublicKeyInfoDer,\n\t\t\tparsed.signatureValue,\n\t\t\tparsed.responseDataDer,\n\t\t);\n\t} catch {\n\t\treturn verifyOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP response signature verification failed',\n\t\t);\n\t}\n\tif (!verifiedResult.ok) {\n\t\tif (verifiedResult.code === 'verification_error') {\n\t\t\treturn verifyOcspResponseFailureResult(\n\t\t\t\t'signature_invalid',\n\t\t\t\t'OCSP response signature verification failed',\n\t\t\t);\n\t\t}\n\t\treturn verifyOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP response signature uses unsupported algorithm parameters',\n\t\t);\n\t}\n\treturn verifiedResult.valid\n\t\t? { ok: true, value: parsed }\n\t\t: verifyOcspResponseFailureResult(\n\t\t\t\t'signature_invalid',\n\t\t\t\t'OCSP response signature does not verify',\n\t\t\t);\n}\n\n/**\n * Full OCSP response validation: response status check, signature verification,\n * responder ID binding (byName or byKeyHash), delegated-responder chain and\n * ocspSigning EKU checks, `producedAt`/`thisUpdate`/`nextUpdate` freshness,\n * nonce match, and request-coverage completeness.\n *\n * @example\n * ```ts\n * import { validateOcspResponse } from 'micro509';\n *\n * const result = await validateOcspResponse({\n * response: ocspResponseDer,\n * issuerCertificate: caPem,\n * request: ocspRequestDer,\n * });\n * if (result.ok) {\n * const entry = result.value.responses?.[0];\n * console.log(entry?.certStatus); // 'good' | 'revoked' | 'unknown'\n * }\n * ```\n */\nexport async function validateOcspResponse(\n\tinput: ValidateOcspResponseInput,\n): Promise<ValidateOcspResponseResult> {\n\tlet parsedResponse: ParsedOcspResponse;\n\ttry {\n\t\tparsedResponse = normalizeOcspResponse(input.response);\n\t} catch {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP response signed content is malformed',\n\t\t);\n\t}\n\tif (parsedResponse.responseStatus !== 'successful') {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'response_status_invalid',\n\t\t\t`OCSP response status is ${parsedResponse.responseStatus}`,\n\t\t);\n\t}\n\tlet issuer: ParsedCertificate;\n\ttry {\n\t\tissuer = await normalizeCertificate(input.issuerCertificate);\n\t} catch {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'issuer certificate input is malformed',\n\t\t);\n\t}\n\tlet resolvedResponder: OcspCertificateSource;\n\ttry {\n\t\tresolvedResponder =\n\t\t\tinput.responderCertificate ??\n\t\t\t(await findMatchingOcspResponderCertificate(\n\t\t\t\tparsedResponse.certificates,\n\t\t\t\tparsedResponse.responderId,\n\t\t\t)) ??\n\t\t\tparsedResponse.certificates?.[0] ??\n\t\t\tinput.issuerCertificate;\n\t} catch {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP responder certificate input is malformed',\n\t\t);\n\t}\n\tlet signer: ParsedCertificate;\n\ttry {\n\t\tsigner = await normalizeCertificate(resolvedResponder);\n\t} catch {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP responder certificate input is malformed',\n\t\t);\n\t}\n\tconst signature = await verifyOcspResponse(parsedResponse, signer);\n\tif (!signature.ok) {\n\t\treturn validateOcspResponseFailureResult(signature.code, signature.message);\n\t}\n\tlet responderBinding:\n\t\t| Extract<ValidateOcspResponseResult, { readonly ok: false }>\n\t\t| { readonly ok: true };\n\ttry {\n\t\tresponderBinding = await validateOcspResponderIdBinding(parsedResponse.responderId, signer);\n\t} catch {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP responder certificate input is malformed',\n\t\t);\n\t}\n\tif (!responderBinding.ok) {\n\t\treturn responderBinding;\n\t}\n\tif (!isSameOcspCertificate(signer, issuer)) {\n\t\tconst allowChainedResponderCertificate = input.allowChainedResponderCertificate === true;\n\t\tif (!allowChainedResponderCertificate && !isDirectlyIssuedByOcspIssuer(signer, issuer)) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'responder_chain_invalid',\n\t\t\t\t'Delegated OCSP responder must be directly issued by issuer certificate',\n\t\t\t);\n\t\t}\n\t\tconst chain = await verifyCertificateChain({\n\t\t\tleaf: signer.der,\n\t\t\tintermediates: allowChainedResponderCertificate\n\t\t\t\t? buildOcspResponderIntermediates(parsedResponse.certificates, signer, issuer)\n\t\t\t\t: [],\n\t\t\troots: [issuer.der],\n\t\t});\n\t\tif (!chain.ok) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'responder_chain_invalid',\n\t\t\t\t'OCSP responder certificate chain does not validate',\n\t\t\t);\n\t\t}\n\t\tif (signer.extendedKeyUsage === undefined || !signer.extendedKeyUsage.includes('ocspSigning')) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'ocsp_signing_missing',\n\t\t\t\t'Delegated OCSP responder lacks ocspSigning EKU',\n\t\t\t);\n\t\t}\n\t}\n\tconst at = input.at ?? new Date();\n\tconst skew = input.clockSkewMs ?? 0;\n\tif (\n\t\tparsedResponse.producedAt !== undefined &&\n\t\tparsedResponse.producedAt.getTime() - skew > at.getTime()\n\t) {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'stale_response',\n\t\t\t'OCSP response producedAt is later than requested time',\n\t\t);\n\t}\n\tfor (const response of parsedResponse.responses ?? []) {\n\t\tlet expected: ParsedOcspCertId;\n\t\ttry {\n\t\t\texpected = await buildParsedOcspCertId(\n\t\t\t\tresponse.certId.hashAlgorithmOid,\n\t\t\t\tissuer,\n\t\t\t\tresponse.certId.serialNumberHex,\n\t\t\t);\n\t\t} catch {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'signature_invalid',\n\t\t\t\t'OCSP response CertID hash algorithm is unsupported',\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tresponse.certId.issuerNameHashHex !== expected.issuerNameHashHex ||\n\t\t\tresponse.certId.issuerKeyHashHex !== expected.issuerKeyHashHex\n\t\t) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'issuer_mismatch',\n\t\t\t\t'OCSP response certId does not match issuer certificate',\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tresponse.thisUpdate.getTime() - skew > at.getTime() ||\n\t\t\t(response.nextUpdate !== undefined && response.nextUpdate.getTime() + skew < at.getTime())\n\t\t) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'stale_response',\n\t\t\t\t'OCSP response is not valid at requested time',\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tparsedResponse.producedAt !== undefined &&\n\t\t\tresponse.nextUpdate !== undefined &&\n\t\t\tparsedResponse.producedAt.getTime() - skew > response.nextUpdate.getTime()\n\t\t) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'stale_response',\n\t\t\t\t'OCSP response producedAt is later than nextUpdate',\n\t\t\t);\n\t\t}\n\t}\n\tif (hasDuplicateOcspResponseCertificateSerial(parsedResponse.responses ?? [])) {\n\t\treturn validateOcspResponseFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'OCSP response contains multiple status entries for the same certificate',\n\t\t);\n\t}\n\tif (input.request !== undefined) {\n\t\tlet request: ParsedOcspRequest;\n\t\ttry {\n\t\t\trequest = normalizeOcspRequest(input.request);\n\t\t} catch {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'request_mismatch',\n\t\t\t\t'OCSP request input is malformed',\n\t\t\t);\n\t\t}\n\t\tif (request.nonce !== undefined && request.nonce !== parsedResponse.nonce) {\n\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t'nonce_mismatch',\n\t\t\t\t'OCSP response nonce does not match request nonce',\n\t\t\t);\n\t\t}\n\t\tconst requestIds = new Set(request.requests.map((entry) => serializeCertId(entry)));\n\t\tconst responseIds = new Set(\n\t\t\t(parsedResponse.responses ?? []).map((response) => serializeCertId(response.certId)),\n\t\t);\n\t\tfor (const response of parsedResponse.responses ?? []) {\n\t\t\tif (!requestIds.has(serializeCertId(response.certId))) {\n\t\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t\t'request_mismatch',\n\t\t\t\t\t'OCSP response includes a certId not present in request',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tfor (const requestId of requestIds) {\n\t\t\tif (!responseIds.has(requestId)) {\n\t\t\t\treturn validateOcspResponseFailureResult(\n\t\t\t\t\t'request_mismatch',\n\t\t\t\t\t'OCSP response does not cover every requested certId',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\treturn { ok: true, value: parsedResponse };\n}\n\n/** Builds a `VerifyOcspResponseFailureResult`. */\nfunction verifyOcspResponseFailureResult(\n\tcode: 'signature_invalid',\n\tmessage: string,\n): ErrorResult<'signature_invalid', Record<never, never>, VerifyOcspResponseFailure> {\n\tconst error: VerifyOcspResponseFailure = {\n\t\tok: false,\n\t\tcode,\n\t\tmessage,\n\t};\n\treturn { ok: false, error, code, message };\n}\n\n/** Builds a `ValidateOcspResponseFailureResult`. */\nfunction validateOcspResponseFailureResult(\n\tcode:\n\t\t| 'response_status_invalid'\n\t\t| 'signature_invalid'\n\t\t| 'responder_id_mismatch'\n\t\t| 'nonce_mismatch'\n\t\t| 'request_mismatch'\n\t\t| 'issuer_mismatch'\n\t\t| 'responder_chain_invalid'\n\t\t| 'ocsp_signing_missing'\n\t\t| 'stale_response',\n\tmessage: string,\n): ErrorResult<\n\t| 'response_status_invalid'\n\t| 'signature_invalid'\n\t| 'responder_id_mismatch'\n\t| 'nonce_mismatch'\n\t| 'request_mismatch'\n\t| 'issuer_mismatch'\n\t| 'responder_chain_invalid'\n\t| 'ocsp_signing_missing'\n\t| 'stale_response',\n\tRecord<never, never>,\n\tValidateOcspResponseFailure\n> {\n\tconst error: ValidateOcspResponseFailure = {\n\t\tok: false,\n\t\tcode,\n\t\tmessage,\n\t};\n\treturn { ok: false, error, code, message };\n}\n\n/** Accepts PEM, DER, or already-parsed OCSP response and returns a parsed response. */\nfunction normalizeOcspResponse(\n\tresponse: string | Uint8Array | ParsedOcspResponse,\n): ParsedOcspResponse {\n\tif (typeof response === 'string') {\n\t\treturn parseOcspResponsePem(response);\n\t}\n\tif (response instanceof Uint8Array) {\n\t\treturn parseOcspResponseDer(response);\n\t}\n\tif (hasReparseableOcspResponseShape(response)) {\n\t\treturn parseOcspResponseDer(new Uint8Array(response.der));\n\t}\n\tthrow new Error('OCSP response input is malformed');\n}\n\n/** Accepts PEM, DER, or already-parsed OCSP request and returns a parsed request. */\nfunction normalizeOcspRequest(request: OcspRequestSource): ParsedOcspRequest {\n\tif (typeof request === 'string') {\n\t\treturn parseOcspRequestPem(request);\n\t}\n\tif (request instanceof Uint8Array) {\n\t\treturn parseOcspRequestDer(request);\n\t}\n\tif (hasReparseableOcspRequestShape(request)) {\n\t\treturn parseOcspRequestDer(new Uint8Array(request.der));\n\t}\n\tthrow new Error('OCSP request input is malformed');\n}\n\nfunction parseSignedOcspResponseData(responseDataDer: Uint8Array): {\n\treadonly responderId: ParsedOcspResponderId;\n\treadonly producedAt: Date;\n\treadonly responses: readonly ParsedOcspSingleResponse[];\n\treadonly nonce?: string;\n} {\n\tconst responseDataChildren = readSequenceChildren(responseDataDer);\n\tif (responseDataChildren.length < 3 || responseDataChildren.length > 5) {\n\t\tthrow new Error('Malformed OCSP responseData');\n\t}\n\tlet index = 0;\n\tif (responseDataChildren[index]?.tag === 0xa0) {\n\t\tconst versionWrapper = requireElement(responseDataChildren[index], 'version');\n\t\tconst versionFields = childrenOf(responseDataDer, versionWrapper);\n\t\tconst versionElement = requireElement(versionFields[0], 'version');\n\t\tif (versionFields.length !== 1 || versionElement.tag !== 0x02) {\n\t\t\tthrow new Error('version must use INTEGER');\n\t\t}\n\t\tif (decodeNonNegativeIntegerNumber(versionElement.value, 'OCSP response version') !== 0) {\n\t\t\tthrow new Error('Unsupported OCSP response version');\n\t\t}\n\t\tindex += 1;\n\t}\n\tconst responderIdElement = requireElement(responseDataChildren[index], 'responderID');\n\tconst responderId = parseOcspResponderId(responseDataDer, responderIdElement);\n\tindex += 1;\n\tconst producedAtElement = requireElement(responseDataChildren[index], 'producedAt');\n\tconst responsesElement = requireElement(responseDataChildren[index + 1], 'responses');\n\tif (responsesElement.tag !== 0x30) {\n\t\tthrow new Error('responses must use SEQUENCE');\n\t}\n\tif (childrenOf(responseDataDer, responsesElement).length === 0) {\n\t\tthrow new Error('responses must not be empty');\n\t}\n\tconst responseExtensions = responseDataChildren[index + 2];\n\tif (responseExtensions !== undefined && responseExtensions.tag !== 0xa1) {\n\t\tthrow new Error('Malformed OCSP responseData');\n\t}\n\tif (responseDataChildren.length !== index + 2 + (responseExtensions === undefined ? 0 : 1)) {\n\t\tthrow new Error('Malformed OCSP responseData');\n\t}\n\tconst nonce =\n\t\tresponseExtensions === undefined\n\t\t\t? undefined\n\t\t\t: parseOcspNonceFromExtensions(responseDataDer, responseExtensions);\n\tconst parsedResponses = childrenOf(responseDataDer, responsesElement).map((singleResponse) =>\n\t\tparseSingleResponse(responseDataDer, singleResponse),\n\t);\n\tassertUniqueOcspResponseCertIds(parsedResponses);\n\treturn {\n\t\tresponderId,\n\t\tproducedAt: parseTime(producedAtElement),\n\t\tresponses: parsedResponses,\n\t\t...(nonce === undefined ? {} : { nonce }),\n\t};\n}\n\n/** Searches embedded certificates for one whose subject or key hash matches the responder ID. */\nasync function findMatchingOcspResponderCertificate(\n\tcertificates: readonly ParsedCertificate[] | undefined,\n\tresponderId: ParsedOcspResponderId | undefined,\n): Promise<ParsedCertificate | undefined> {\n\tif (certificates === undefined || responderId === undefined) {\n\t\treturn undefined;\n\t}\n\tfor (const certificate of certificates) {\n\t\tif (await matchesOcspResponderId(responderId, certificate)) {\n\t\t\treturn certificate;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Verifies that the signer certificate matches the response's responder ID (byName or byKeyHash). */\nasync function validateOcspResponderIdBinding(\n\tresponderId: ParsedOcspResponderId | undefined,\n\tsigner: ParsedCertificate,\n): Promise<Extract<ValidateOcspResponseResult, { readonly ok: false }> | { readonly ok: true }> {\n\tif (responderId === undefined) {\n\t\treturn { ok: true };\n\t}\n\tif (await matchesOcspResponderId(responderId, signer)) {\n\t\treturn { ok: true };\n\t}\n\treturn responderId.type === 'byName'\n\t\t? validateOcspResponseFailureResult(\n\t\t\t\t'responder_id_mismatch',\n\t\t\t\t'OCSP responder certificate subject does not match responderID byName',\n\t\t\t)\n\t\t: validateOcspResponseFailureResult(\n\t\t\t\t'responder_id_mismatch',\n\t\t\t\t'OCSP responder certificate public key does not match responderID byKeyHash',\n\t\t\t);\n}\n\n/** Returns `true` if the certificate matches the responder ID (subject name or key hash). */\nasync function matchesOcspResponderId(\n\tresponderId: ParsedOcspResponderId,\n\tcertificate: ParsedCertificate,\n): Promise<boolean> {\n\tif (responderId.type === 'byName') {\n\t\treturn compareOcspResponderNames(responderId.name, certificate.subject);\n\t}\n\tconst certificateKeyHashHex = toHex(\n\t\tawait digestBytes('SHA-1', extractSubjectPublicKeyBytes(certificate.subjectPublicKeyInfoDer)),\n\t);\n\treturn certificateKeyHashHex === responderId.keyHashHex;\n}\n\n/** Identity check — same serial, issuer, subject, and SPKI. */\nfunction isSameOcspCertificate(left: ParsedCertificate, right: ParsedCertificate): boolean {\n\treturn (\n\t\tleft.serialNumberHex === right.serialNumberHex &&\n\t\tcompareDistinguishedNames(left.issuer, right.issuer) &&\n\t\tcompareDistinguishedNames(left.subject, right.subject) &&\n\t\tleft.subjectPublicKeyInfoDer.length === right.subjectPublicKeyInfoDer.length &&\n\t\tleft.subjectPublicKeyInfoDer.every(\n\t\t\t(byte, index) => byte === right.subjectPublicKeyInfoDer[index],\n\t\t)\n\t);\n}\n\n/** Returns `true` if `signer` was directly issued by `issuer` (name + AKI match). */\nfunction isDirectlyIssuedByOcspIssuer(\n\tsigner: ParsedCertificate,\n\tissuer: ParsedCertificate,\n): boolean {\n\tif (!compareDistinguishedNames(signer.issuer, issuer.subject)) {\n\t\treturn false;\n\t}\n\tif (\n\t\tsigner.authorityKeyIdentifier !== undefined &&\n\t\tissuer.subjectKeyIdentifier !== undefined &&\n\t\tsigner.authorityKeyIdentifier !== issuer.subjectKeyIdentifier\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n/** Filters embedded certificates to produce an intermediate chain (excluding signer and issuer). */\nfunction buildOcspResponderIntermediates(\n\tcertificates: readonly ParsedCertificate[] | undefined,\n\tsigner: ParsedCertificate,\n\tissuer: ParsedCertificate,\n): readonly Uint8Array[] {\n\tif (certificates === undefined) {\n\t\treturn [];\n\t}\n\tconst intermediates: Uint8Array[] = [];\n\tfor (const certificate of certificates) {\n\t\tif (isSameOcspCertificate(certificate, signer) || isSameOcspCertificate(certificate, issuer)) {\n\t\t\tcontinue;\n\t\t}\n\t\tintermediates.push(certificate.der);\n\t}\n\treturn intermediates;\n}\n\n/** DER-encodes a CertID SEQUENCE (hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber). */\nasync function encodeOcspCertId(\n\tcertificate: ParsedCertificate,\n\tissuer: ParsedCertificate,\n\thashAlgorithm: OcspHashAlgorithm,\n): Promise<Uint8Array> {\n\tconst hashAlgorithmOid = hashAlgorithm === 'SHA-1' ? OIDS.sha1 : OIDS.sha256;\n\tconst parsed = await buildParsedOcspCertId(hashAlgorithmOid, issuer, certificate.serialNumberHex);\n\treturn sequence([\n\t\tsequence([objectIdentifier(hashAlgorithmOid), nullValue()]),\n\t\toctetString(hexToBytes(parsed.issuerNameHashHex)),\n\t\toctetString(hexToBytes(parsed.issuerKeyHashHex)),\n\t\tinteger(hexToBytes(parsed.serialNumberHex)),\n\t]);\n}\n\n/** Computes issuer name/key hashes for a CertID given the hash algorithm OID and issuer certificate. */\nasync function buildParsedOcspCertId(\n\thashAlgorithmOid: string,\n\tissuer: ParsedCertificate,\n\tserialNumberHex: string,\n): Promise<ParsedOcspCertId> {\n\tconst hashAlgorithm = ocspHashAlgorithmFromOid(hashAlgorithmOid);\n\treturn {\n\t\thashAlgorithmOid,\n\t\thashAlgorithmName: describeHashAlgorithm(hashAlgorithmOid),\n\t\tissuerNameHashHex: toHex(await digestBytes(hashAlgorithm, hexToBytes(issuer.subject.derHex))),\n\t\tissuerKeyHashHex: toHex(\n\t\t\tawait digestBytes(\n\t\t\t\thashAlgorithm,\n\t\t\t\textractSubjectPublicKeyBytes(issuer.subjectPublicKeyInfoDer),\n\t\t\t),\n\t\t),\n\t\tserialNumberHex,\n\t};\n}\n\n/** Hashes `bytes` with the given WebCrypto algorithm name. */\nasync function digestBytes(algorithm: OcspHashAlgorithm, bytes: Uint8Array): Promise<Uint8Array> {\n\treturn new Uint8Array(await getCrypto().subtle.digest(algorithm, toArrayBuffer(bytes)));\n}\n\n/** DER-encodes a SingleResponse (certId, certStatus, thisUpdate, optional nextUpdate). */\nasync function encodeSingleResponse(\n\tcertificate: ParsedCertificate,\n\tissuer: ParsedCertificate,\n\tinput: CreateOcspSingleResponseInput,\n\thashAlgorithm: OcspHashAlgorithm,\n): Promise<Uint8Array> {\n\tconst certId = await encodeOcspCertId(certificate, issuer, hashAlgorithm);\n\tconst certStatus = encodeOcspCertStatus(input);\n\treturn sequence([\n\t\tcertId,\n\t\tcertStatus,\n\t\ttime(input.thisUpdate ?? new Date()),\n\t\t...(input.nextUpdate === undefined ? [] : [explicitContext(0, time(input.nextUpdate))]),\n\t]);\n}\n\n/** DER-encodes the CertStatus CHOICE (good [0], revoked [1], unknown [2]). */\nfunction encodeOcspCertStatus(input: CreateOcspSingleResponseInput): Uint8Array {\n\tswitch (input.certStatus) {\n\t\tcase 'good':\n\t\t\treturn tlv(0x80, new Uint8Array());\n\t\tcase 'unknown':\n\t\t\treturn tlv(0x82, new Uint8Array());\n\t\tcase 'revoked': {\n\t\t\tconst revokedFields: Uint8Array[] = [time(input.revokedAt ?? input.thisUpdate ?? new Date())];\n\t\t\tif (input.revocationReasonCode !== undefined) {\n\t\t\t\trevokedFields.push(\n\t\t\t\t\texplicitContext(0, tlv(0x0a, Uint8Array.of(input.revocationReasonCode))),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn tlv(0xa1, concatBytes(revokedFields));\n\t\t}\n\t}\n}\n\n/** Accepts PEM, DER, or already-parsed certificate and returns a parsed certificate. */\nfunction normalizeCertificate(source: OcspCertificateSource): ParsedCertificate {\n\tif (hasParsedCertificateShape(source)) {\n\t\treturn parseCertificateDer(new Uint8Array(source.der));\n\t}\n\treturn parseCertificateFromSource(source);\n}\n\n/** Type guard: distinguishes a `ParsedCertificate` from raw `Uint8Array`. */\nfunction hasParsedCertificateShape(value: OcspCertificateSource): value is ParsedCertificate {\n\treturn typeof value !== 'string' && 'subjectPublicKeyInfoDer' in value;\n}\n\n/** Decodes a DER-encoded CertID SEQUENCE into a {@linkcode ParsedOcspCertId}. */\nfunction parseOcspCertId(der: Uint8Array): ParsedOcspCertId {\n\tconst root = readRootElement(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (root.tag !== 0x30) {\n\t\tthrow new Error('CertID must use SEQUENCE');\n\t}\n\tconst children = childrenOf(der, root);\n\tif (children.length !== 4) {\n\t\tthrow new Error(\n\t\t\t'CertID must contain hashAlgorithm, issuerNameHash, issuerKeyHash, and serialNumber',\n\t\t);\n\t}\n\tconst hashAlgorithm = requireElement(children[0], 'hashAlgorithm');\n\tif (hashAlgorithm.tag !== 0x30) {\n\t\tthrow new Error('hashAlgorithm must use SEQUENCE');\n\t}\n\tconst algorithmChildren = childrenOf(der, hashAlgorithm);\n\tif (algorithmChildren.length < 1 || algorithmChildren.length > 2) {\n\t\tthrow new Error('Malformed hashAlgorithm');\n\t}\n\tconst algorithmOid = requireElement(algorithmChildren[0], 'hashAlgorithm OID');\n\tconst hashAlgorithmOid = decodeObjectIdentifier(algorithmOid.value);\n\tif (requireElement(children[1], 'issuerNameHash').tag !== 0x04) {\n\t\tthrow new Error('issuerNameHash must use OCTET STRING');\n\t}\n\tif (requireElement(children[2], 'issuerKeyHash').tag !== 0x04) {\n\t\tthrow new Error('issuerKeyHash must use OCTET STRING');\n\t}\n\tconst serialNumber = requireElement(children[3], 'serialNumber');\n\tif (serialNumber.tag !== 0x02) {\n\t\tthrow new Error('serialNumber must use INTEGER');\n\t}\n\treturn {\n\t\thashAlgorithmOid,\n\t\thashAlgorithmName: describeHashAlgorithm(hashAlgorithmOid),\n\t\tissuerNameHashHex: toHex(requireElement(children[1], 'issuerNameHash').value),\n\t\tissuerKeyHashHex: toHex(requireElement(children[2], 'issuerKeyHash').value),\n\t\tserialNumberHex: toHex(serialNumber.value),\n\t};\n}\n\n/** Decodes a SingleResponse from its ASN.1 element within the ResponseData. */\nfunction parseSingleResponse(source: Uint8Array, element: DerElement): ParsedOcspSingleResponse {\n\tconst children = childrenOf(source, element);\n\tif (children.length < 3 || children.length > 5) {\n\t\tthrow new Error('Malformed OCSP SingleResponse');\n\t}\n\tconst certId = requireElement(children[0], 'certId');\n\tconst certStatus = requireElement(children[1], 'certStatus');\n\tconst thisUpdate = requireElement(children[2], 'thisUpdate');\n\tlet cursor = 3;\n\tconst nextUpdateElement = children[cursor]?.tag === 0xa0 ? children[cursor] : undefined;\n\tif (nextUpdateElement !== undefined) {\n\t\tvalidateOcspSingleResponseNextUpdate(source, nextUpdateElement);\n\t\tcursor += 1;\n\t}\n\tconst singleExtensions = children[cursor];\n\tif (singleExtensions !== undefined && singleExtensions.tag !== 0xa1) {\n\t\tthrow new Error('Malformed OCSP SingleResponse');\n\t}\n\tif (children.length !== cursor + (singleExtensions === undefined ? 0 : 1)) {\n\t\tthrow new Error('Malformed OCSP SingleResponse');\n\t}\n\tlet revokedAt: Date | undefined;\n\tlet revocationReasonCode: number | undefined;\n\tif (certStatus.tag === 0x80) {\n\t\tif (certStatus.value.length !== 0) {\n\t\t\tthrow new Error('OCSP good certStatus must be empty');\n\t\t}\n\t\treturn {\n\t\t\tcertId: parseOcspCertId(source.slice(certId.start - certId.headerLength, certId.end)),\n\t\t\tcertStatus: 'good',\n\t\t\tthisUpdate: parseTime(thisUpdate),\n\t\t\t...(nextUpdateElement === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tnextUpdate: parseTime(\n\t\t\t\t\t\t\trequireElement(childrenOf(source, nextUpdateElement)[0], 'nextUpdate'),\n\t\t\t\t\t\t),\n\t\t\t\t\t}),\n\t\t};\n\t}\n\tif (certStatus.tag === 0xa1) {\n\t\tconst revokedInfo = childrenOf(source, certStatus);\n\t\tif (revokedInfo.length < 1 || revokedInfo.length > 2) {\n\t\t\tthrow new Error('Malformed OCSP revoked certStatus');\n\t\t}\n\t\trevokedAt = parseTime(requireElement(revokedInfo[0], 'revocationTime'));\n\t\tconst reason = revokedInfo[1];\n\t\tif (reason?.tag === 0xa0) {\n\t\t\tconst reasonChildren = childrenOf(source, reason);\n\t\t\tconst enumerated = requireElement(reasonChildren[0], 'revocationReason');\n\t\t\tif (reasonChildren.length !== 1 || enumerated.tag !== 0x0a) {\n\t\t\t\tthrow new Error('revocationReason must use ENUMERATED');\n\t\t\t}\n\t\t\trevocationReasonCode = decodeNonNegativeIntegerNumber(\n\t\t\t\tenumerated.value,\n\t\t\t\t'OCSP revocationReason',\n\t\t\t);\n\t\t} else if (reason !== undefined) {\n\t\t\tthrow new Error('Malformed OCSP revoked certStatus');\n\t\t}\n\t} else if (certStatus.tag !== 0x82) {\n\t\tthrow new Error(`Unsupported OCSP certStatus tag: ${String(certStatus.tag)}`);\n\t} else if (certStatus.value.length !== 0) {\n\t\tthrow new Error('OCSP unknown certStatus must be empty');\n\t}\n\treturn {\n\t\tcertId: parseOcspCertId(source.slice(certId.start - certId.headerLength, certId.end)),\n\t\tcertStatus: certStatus.tag === 0x82 ? 'unknown' : 'revoked',\n\t\tthisUpdate: parseTime(thisUpdate),\n\t\t...(nextUpdateElement === undefined\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tnextUpdate: parseTime(\n\t\t\t\t\t\trequireElement(childrenOf(source, nextUpdateElement)[0], 'nextUpdate'),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t...(revokedAt === undefined ? {} : { revokedAt }),\n\t\t...(revocationReasonCode === undefined ? {} : { revocationReasonCode }),\n\t};\n}\n\n/** Decodes a ResponderID from its context-tagged ASN.1 element (byName [1] or byKeyHash [2]). */\nfunction parseOcspResponderId(source: Uint8Array, element: DerElement): ParsedOcspResponderId {\n\tswitch (element.tag) {\n\t\tcase 0x82:\n\t\t\tif (element.value.length === 0) {\n\t\t\t\tthrow new Error('ResponderID byKeyHash must not be empty');\n\t\t\t}\n\t\t\treturn { type: 'byKeyHash', keyHashHex: toHex(element.value) };\n\t\tcase 0xa1:\n\t\t\tif (childrenOf(source, element).length !== 1) {\n\t\t\t\tthrow new Error('ResponderID byName must wrap exactly one Name');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttype: 'byName',\n\t\t\t\tname: parseResponderName(\n\t\t\t\t\tsource,\n\t\t\t\t\trequireElement(childrenOf(source, element)[0], 'ResponderID byName'),\n\t\t\t\t),\n\t\t\t};\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported OCSP responderID tag: ${String(element.tag)}`);\n\t}\n}\n\n/** Decodes a Name SEQUENCE from the ResponderID byName form. */\nfunction parseResponderName(source: Uint8Array, element: DerElement): ParsedName {\n\tif (element.tag !== 0x30) {\n\t\tthrow new Error('ResponderID byName must use Name SEQUENCE');\n\t}\n\tconst rdns: ParsedRelativeDistinguishedName[] = [];\n\tconst attributes: ParsedNameAttribute[] = [];\n\tconst values: ParsedName['values'] = {};\n\tfor (const setElement of childrenOf(source, element)) {\n\t\tconst rdn = parseResponderNameAttributeSet(source, setElement);\n\t\trdns.push(rdn);\n\t\tfor (const attribute of rdn.attributes) {\n\t\t\tattributes.push(attribute);\n\t\t\tif (attribute.key !== undefined && values[attribute.key] === undefined) {\n\t\t\t\tvalues[attribute.key] = attribute.value;\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tderHex: toHex(source.slice(element.start - element.headerLength, element.end)),\n\t\trdns,\n\t\tattributes,\n\t\tvalues,\n\t};\n}\n\n/** Decodes one RDN SET from a responder name. */\nfunction parseResponderNameAttributeSet(\n\tsource: Uint8Array,\n\tsetElement: DerElement,\n): ParsedRelativeDistinguishedName {\n\tconst attributes: ParsedNameAttribute[] = [];\n\tconst values: ParsedRelativeDistinguishedName['values'] = {};\n\tfor (const attributeSequence of childrenOf(source, setElement)) {\n\t\tconst parts = childrenOf(source, attributeSequence);\n\t\tconst oid = decodeObjectIdentifier(requireElement(parts[0], 'name OID').value);\n\t\tconst valueElement = requireElement(parts[1], 'name value');\n\t\tconst key = responderNameKeyFromOid(oid);\n\t\tconst value = decodeString(valueElement.tag, valueElement.value);\n\t\tconst attribute: ParsedNameAttribute =\n\t\t\tkey === undefined\n\t\t\t\t? { oid, valueTag: valueElement.tag, value }\n\t\t\t\t: { oid, key, valueTag: valueElement.tag, value };\n\t\tattributes.push(attribute);\n\t\tif (key !== undefined && values[key] === undefined) {\n\t\t\tvalues[key] = value;\n\t\t}\n\t}\n\treturn {\n\t\tderHex: toHex(source.slice(setElement.start - setElement.headerLength, setElement.end)),\n\t\tattributes,\n\t\tvalues,\n\t};\n}\n\n/** RDN-by-RDN responder name comparison with RFC 4518 string prep. */\nfunction compareOcspResponderNames(left: ParsedName, right: ParsedName): boolean {\n\tif (left.rdns.length !== right.rdns.length) {\n\t\treturn false;\n\t}\n\tfor (let index = 0; index < left.rdns.length; index += 1) {\n\t\tconst leftRdn = left.rdns[index];\n\t\tconst rightRdn = right.rdns[index];\n\t\tif (leftRdn === undefined || rightRdn === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!compareOcspRelativeDistinguishedNames(leftRdn, rightRdn)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/** Set-equality comparison for RDN attribute sets (order-independent). */\nfunction compareOcspRelativeDistinguishedNames(\n\tleft: ParsedRelativeDistinguishedName,\n\tright: ParsedRelativeDistinguishedName,\n): boolean {\n\tif (left.attributes.length !== right.attributes.length) {\n\t\treturn false;\n\t}\n\tconst matched = new Array(right.attributes.length).fill(false);\n\tfor (const leftAttribute of left.attributes) {\n\t\tlet found = false;\n\t\tfor (let index = 0; index < right.attributes.length; index += 1) {\n\t\t\tconst rightAttribute = right.attributes[index];\n\t\t\tif (rightAttribute === undefined || matched[index]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!compareOcspNameAttributeValue(leftAttribute, rightAttribute)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmatched[index] = true;\n\t\t\tfound = true;\n\t\t\tbreak;\n\t\t}\n\t\tif (!found) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/** Compares two name attributes with RFC 4518 string prep for directory-string types. */\nfunction compareOcspNameAttributeValue(\n\tleft: ParsedNameAttribute,\n\tright: ParsedNameAttribute,\n): boolean {\n\tif (left.oid !== right.oid) {\n\t\treturn false;\n\t}\n\tif (isOcspDirectoryStringTag(left.valueTag) && isOcspDirectoryStringTag(right.valueTag)) {\n\t\tconst preparedLeft = prepareOcspNameCompareString(left.value);\n\t\tconst preparedRight = prepareOcspNameCompareString(right.value);\n\t\tif (preparedLeft === undefined || preparedRight === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\treturn preparedLeft === preparedRight;\n\t}\n\treturn left.valueTag === right.valueTag && left.value === right.value;\n}\n\n/** Returns `true` for UTF8String (0x0c) and PrintableString (0x13). */\nfunction isOcspDirectoryStringTag(tag: number): boolean {\n\treturn tag === 0x0c || tag === 0x13;\n}\n\n/** NFKC-normalises, lowercases, trims, and collapses whitespace for RFC 4518 name comparison. */\nfunction prepareOcspNameCompareString(value: string): string | undefined {\n\tconst normalized = value.normalize('NFKC');\n\tif (/[^\\P{Cc}\\t\\n\\r]/u.test(normalized)) {\n\t\treturn undefined;\n\t}\n\treturn normalized.toLowerCase().trim().replace(/\\s+/gu, ' ');\n}\n\n/** Maps an X.500 attribute type OID to its friendly key name for responder name parsing. */\nfunction responderNameKeyFromOid(oid: string): ParsedNameAttribute['key'] {\n\tswitch (oid) {\n\t\tcase OIDS.commonName:\n\t\t\treturn 'commonName';\n\t\tcase OIDS.surname:\n\t\t\treturn 'surname';\n\t\tcase OIDS.serialNumber:\n\t\t\treturn 'serialNumber';\n\t\tcase OIDS.countryName:\n\t\t\treturn 'country';\n\t\tcase OIDS.localityName:\n\t\t\treturn 'locality';\n\t\tcase OIDS.stateOrProvinceName:\n\t\t\treturn 'state';\n\t\tcase OIDS.streetAddress:\n\t\t\treturn 'street';\n\t\tcase OIDS.organizationName:\n\t\t\treturn 'organization';\n\t\tcase OIDS.organizationalUnitName:\n\t\t\treturn 'organizationalUnit';\n\t\tcase OIDS.title:\n\t\t\treturn 'title';\n\t\tcase OIDS.givenName:\n\t\t\treturn 'givenName';\n\t\tcase OIDS.emailAddress:\n\t\t\treturn 'emailAddress';\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n/** Extracts the nonce value (as hex) from an OCSP extensions wrapper, if present. */\nfunction parseOcspNonceFromExtensions(source: Uint8Array, element: DerElement): string | undefined {\n\tconst extensionsChildren = childrenOf(source, element);\n\tconst extensionsSequence = requireElement(extensionsChildren[0], 'extensions');\n\tif (extensionsChildren.length !== 1 || extensionsSequence.tag !== 0x30) {\n\t\tthrow new Error('Malformed OCSP extensions');\n\t}\n\tconst seenOids = new Set<string>();\n\tlet nonce: string | undefined;\n\tfor (const extension of childrenOf(source, extensionsSequence)) {\n\t\tconst parts = childrenOf(source, extension);\n\t\tif (parts.length < 2 || parts.length > 3) {\n\t\t\tthrow new Error('Malformed OCSP extension');\n\t\t}\n\t\tif (parts.length === 3 && parts[1]?.tag !== 0x01) {\n\t\t\tthrow new Error('Malformed OCSP extension');\n\t\t}\n\t\tconst oid = decodeObjectIdentifier(requireElement(parts[0], 'extension OID').value);\n\t\tif (seenOids.has(oid)) {\n\t\t\tthrow new Error(`Duplicate OCSP extension OID: ${oid}`);\n\t\t}\n\t\tseenOids.add(oid);\n\t\tconst extnValue = requireElement(parts[parts.length - 1], 'extnValue');\n\t\tif (extnValue.tag !== 0x04) {\n\t\t\tthrow new Error('OCSP extension value must use OCTET STRING');\n\t\t}\n\t\tif (oid !== OIDS.ocspNonce) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst nonceElement = readRootElement(extnValue.value, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\t\tif (nonceElement.tag !== 0x04) {\n\t\t\tthrow new Error('OCSP nonce extension value must use OCTET STRING');\n\t\t}\n\t\tnonce = toHex(nonceElement.value);\n\t}\n\treturn nonce;\n}\n\n/** Decodes the optional `certs [0]` field from a BasicOCSPResponse. */\nfunction parseEmbeddedCertificates(\n\tsource: Uint8Array,\n\telement: DerElement,\n): readonly ParsedCertificate[] {\n\tconst certificates: ParsedCertificate[] = [];\n\tlet offset = element.start;\n\twhile (offset < element.end) {\n\t\tconst child = readElement(source, offset);\n\t\tcertificates.push(parseCertificateDer(source.slice(offset, child.end)));\n\t\toffset = child.end;\n\t}\n\treturn certificates;\n}\n\n/** Extracts the raw public key bytes (without BIT STRING padding byte) from SPKI DER. */\nfunction extractSubjectPublicKeyBytes(spkiDer: Uint8Array): Uint8Array {\n\tconst top = childrenOf(spkiDer, readElement(spkiDer));\n\tconst bitStringElement = requireElement(top[1], 'subjectPublicKey BIT STRING');\n\tif (bitStringElement.tag !== 0x03) {\n\t\tthrow new Error('SPKI missing subjectPublicKey BIT STRING');\n\t}\n\treturn bitStringElement.value.slice(1);\n}\n\n/** Maps an integer response-status code to its {@linkcode OcspResponseStatus} string. */\nfunction ocspResponseStatusFromCode(code: number | undefined): OcspResponseStatus {\n\tswitch (code) {\n\t\tcase 0:\n\t\t\treturn 'successful';\n\t\tcase 1:\n\t\t\treturn 'malformedRequest';\n\t\tcase 2:\n\t\t\treturn 'internalError';\n\t\tcase 3:\n\t\t\treturn 'tryLater';\n\t\tcase 5:\n\t\t\treturn 'sigRequired';\n\t\tcase 6:\n\t\t\treturn 'unauthorized';\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported OCSP responseStatus value: ${String(code)}`);\n\t}\n}\n\nfunction hasReparseableOcspRequestShape(\n\trequest: ParsedOcspRequest,\n): request is ParsedOcspRequest & { readonly der: Uint8Array } {\n\treturn 'der' in request && request.der instanceof Uint8Array;\n}\n\nfunction hasReparseableOcspResponseShape(\n\tresponse: ParsedOcspResponse,\n): response is ParsedOcspResponse & { readonly der: Uint8Array } {\n\treturn 'der' in response && response.der instanceof Uint8Array;\n}\n\nfunction assertUniqueOcspResponseCertIds(responses: readonly ParsedOcspSingleResponse[]): void {\n\tconst seen = new Set<string>();\n\tfor (const response of responses) {\n\t\tconst key = serializeCertId(response.certId);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error('Duplicate OCSP response CertID');\n\t\t}\n\t\tseen.add(key);\n\t}\n}\n\nfunction hasDuplicateOcspResponseCertificateSerial(\n\tresponses: readonly ParsedOcspSingleResponse[],\n): boolean {\n\tconst seen = new Set<string>();\n\tfor (const response of responses) {\n\t\tconst serial = normalizeHex(response.certId.serialNumberHex);\n\t\tif (seen.has(serial)) {\n\t\t\treturn true;\n\t\t}\n\t\tseen.add(serial);\n\t}\n\treturn false;\n}\n\nfunction validateOcspRequestorName(source: Uint8Array, element: DerElement): void {\n\tconst children = childrenOf(source, element);\n\tconst requestorName = requireElement(children[0], 'requestorName');\n\tif (children.length !== 1 || (requestorName.tag & 0xc0) !== 0x80) {\n\t\tthrow new Error('requestorName must wrap exactly one GeneralName');\n\t}\n}\n\nfunction validateOcspOptionalSignature(source: Uint8Array, element: DerElement): void {\n\tconst wrapperChildren = childrenOf(source, element);\n\tconst signatureSequence = requireElement(wrapperChildren[0], 'optionalSignature');\n\tif (wrapperChildren.length !== 1 || signatureSequence.tag !== 0x30) {\n\t\tthrow new Error('optionalSignature must wrap exactly one Signature');\n\t}\n\tconst signatureChildren = childrenOf(source, signatureSequence);\n\tif (\n\t\tsignatureChildren.length < 2 ||\n\t\tsignatureChildren.length > 3 ||\n\t\tsignatureChildren[0]?.tag !== 0x30 ||\n\t\t(signatureChildren[2] !== undefined && signatureChildren[2]?.tag !== 0xa0)\n\t) {\n\t\tthrow new Error('Malformed optionalSignature');\n\t}\n\tconst signatureAlgorithm = requireElement(signatureChildren[0], 'signatureAlgorithm');\n\tconst signatureValue = requireElement(signatureChildren[1], 'signature');\n\tconst certificates = signatureChildren[2];\n\tvalidateAlgorithmIdentifierShape(source, signatureAlgorithm, 'optionalSignature algorithm');\n\textractBitStringValue(signatureValue);\n\tif (certificates !== undefined) {\n\t\tconst certificateChildren = childrenOf(source, certificates);\n\t\tif (certificateChildren.length !== 1 || certificateChildren[0]?.tag !== 0x30) {\n\t\t\tthrow new Error('optionalSignature certs must use SEQUENCE OF Certificate');\n\t\t}\n\t}\n}\n\nfunction validateOcspSingleResponseNextUpdate(source: Uint8Array, element: DerElement): void {\n\tconst children = childrenOf(source, element);\n\tconst nextUpdate = requireElement(children[0], 'nextUpdate');\n\tif (children.length !== 1 || (nextUpdate.tag !== 0x17 && nextUpdate.tag !== 0x18)) {\n\t\tthrow new Error('nextUpdate must wrap exactly one time value');\n\t}\n}\n\nfunction validateAlgorithmIdentifierShape(\n\tsource: Uint8Array,\n\telement: DerElement,\n\tlabel: string,\n): void {\n\tconst children = childrenOf(source, element);\n\tif (\n\t\telement.tag !== 0x30 ||\n\t\tchildren.length < 1 ||\n\t\tchildren.length > 2 ||\n\t\tchildren[0]?.tag !== 0x06\n\t) {\n\t\tthrow new Error(`${label} must use AlgorithmIdentifier SEQUENCE`);\n\t}\n\tdecodeObjectIdentifier(requireElement(children[0], `${label} OID`).value);\n}\n\nfunction normalizeHex(value: string): string {\n\treturn value.toLowerCase();\n}\n\n/** Maps a hash algorithm OID to the WebCrypto algorithm name. Throws on unsupported OIDs. */\nfunction ocspHashAlgorithmFromOid(oid: string): OcspHashAlgorithm {\n\tswitch (oid) {\n\t\tcase OIDS.sha1:\n\t\t\treturn 'SHA-1';\n\t\tcase OIDS.sha256:\n\t\t\treturn 'SHA-256';\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported OCSP hash algorithm OID: ${oid}`);\n\t}\n}\n\n/** Produces a colon-delimited canonical string for CertID set comparison. */\nfunction serializeCertId(certId: ParsedOcspCertId): string {\n\treturn [\n\t\tcertId.hashAlgorithmOid,\n\t\tcertId.issuerNameHashHex,\n\t\tcertId.issuerKeyHashHex,\n\t\tcertId.serialNumberHex,\n\t].join(':');\n}\n"],"mappings":"8vCAiXA,eAAsB,GACrB,EAC+B,CAC/B,IAAM,EAAgB,EAAM,eAAiB,QACvC,EAA+B,CAAC,EACtC,IAAK,IAAM,KAAW,EAAM,SAAU,CACrC,IAAM,EAAc,MAAM,EAAqB,EAAQ,WAAW,EAC5D,EAAS,MAAM,EAAqB,EAAQ,iBAAiB,EACnE,EAAe,KAAK,EAAS,CAAC,MAAM,EAAiB,EAAa,EAAQ,CAAa,CAAC,CAAC,CAAC,CAC3F,CACA,IAAM,EAAiC,CAAC,EAAS,CAAc,CAAC,EAC5D,EAAM,QAAU,IAAA,IACnB,EAAiB,KAChB,EACC,EACA,EAAS,CACR,EAAS,CAAC,EAAiB,EAAK,SAAS,EAAG,EAAY,EAAY,EAAM,KAAK,CAAC,CAAC,CAAC,CACnF,CAAC,CACF,CACD,EAED,IAAM,EAAM,EAAS,CAAC,EAAS,CAAgB,CAAC,CAAC,EACjD,MAAO,CACN,MACA,IAAK,EAAU,eAAgB,CAAG,EAClC,OAAQ,EAAa,CAAG,CACzB,CACD,CAGA,SAAgB,EAAoB,EAAoC,CACvE,IAAM,EAAM,EAAqB,EAAK,CAAE,SAAA,EAAgC,CAAC,EACzE,GAAI,EAAI,OAAS,GAAK,EAAI,OAAS,EAClC,MAAU,MAAM,wBAAwB,EAEzC,IAAM,EAAa,EAAe,EAAI,GAAI,YAAY,EAChD,EAAoB,EAAI,GAC9B,GAAI,IAAsB,IAAA,IAAa,EAAkB,MAAQ,IAChE,MAAU,MAAM,wBAAwB,EAErC,IAAsB,IAAA,IACzB,GAA8B,EAAK,CAAiB,EAErD,IAAM,EAAc,EAAW,EAAK,CAAU,EAC1C,EAAS,EACb,GAAI,EAAY,EAAO,EAAE,MAAQ,IAAM,CAEtC,IAAM,EAAgB,EAAW,EADV,EAAe,EAAY,GAAS,SACR,CAAC,EAC9C,EAAiB,EAAe,EAAc,GAAI,SAAS,EACjE,GAAI,EAAc,SAAW,GAAK,EAAe,MAAQ,EACxD,MAAU,MAAM,0BAA0B,EAE3C,GAAI,EAA+B,EAAe,MAAO,sBAAsB,IAAM,EACpF,MAAU,MAAM,kCAAkC,EAEnD,GAAU,CACX,CACA,IAAM,EAAgB,EAAY,GAC9B,GAAe,MAAQ,MAC1B,GAA0B,EAAK,CAAa,EAC5C,GAAU,GAEX,IAAM,EAAc,EAAe,EAAY,GAAS,aAAa,EACrE,GAAI,EAAY,MAAQ,GACvB,MAAU,MAAM,+BAA+B,EAEhD,GAAI,EAAW,EAAK,CAAW,CAAC,CAAC,SAAW,EAC3C,MAAU,MAAM,+BAA+B,EAEhD,IAAM,EAAW,EAAW,EAAK,CAAW,CAAC,CAAC,IAAK,GAAY,CAC9D,IAAM,EAAkB,EAAW,EAAK,CAAO,EAI/C,GAHI,EAAgB,OAAS,GAAK,EAAgB,OAAS,GAGvD,EAAgB,KAAO,IAAA,IAAa,EAAgB,EAAE,CAAC,MAAQ,IAClE,MAAU,MAAM,8BAA8B,EAE/C,IAAM,EAAS,EAAe,EAAgB,GAAI,SAAS,EAC3D,OAAO,EAAgB,EAAI,MAAM,EAAO,MAAQ,EAAO,aAAc,EAAO,GAAG,CAAC,CACjF,CAAC,EACD,GAAU,EACV,IAAM,EAAa,EAAY,GAI/B,GAHI,IAAe,IAAA,IAAa,EAAW,MAAQ,KAG/C,EAAY,SAAW,GAAU,IAAe,IAAA,GAAY,EAAI,GACnE,MAAU,MAAM,wBAAwB,EAEzC,IAAM,EACL,IAAe,IAAA,GAAY,IAAA,GAAY,EAA6B,EAAK,CAAU,EACpF,MAAO,CACN,IAAK,IAAI,WAAW,CAAG,EACvB,WACA,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,OAAM,CACxC,CACD,CAGA,SAAgB,EAAoB,EAAgC,CACnE,OAAO,EAAoB,EAAU,eAAgB,CAAG,CAAC,CAC1D,CAGA,SAAgB,EAAqB,EAAqC,CACzE,IAAM,EAAM,EAAqB,EAAK,CAAE,SAAA,EAAgC,CAAC,EACzE,GAAI,EAAI,OAAS,GAAK,EAAI,OAAS,EAClC,MAAU,MAAM,yBAAyB,EAE1C,IAAM,EAAgB,EAAe,EAAI,GAAI,gBAAgB,EAC7D,GAAI,EAAc,MAAQ,GACzB,MAAU,MAAM,oCAAoC,EAErD,IAAM,EAAiB,GACtB,EAA+B,EAAc,MAAO,qBAAqB,CAC1E,EACM,EAAgB,EAAI,GAC1B,GAAI,IAAkB,IAAA,GACrB,MAAO,CAAE,IAAK,IAAI,WAAW,CAAG,EAAG,gBAAe,EAEnD,GAAI,EAAc,MAAQ,IACzB,MAAU,MAAM,yBAAyB,EAE1C,IAAM,EAAuB,EAAW,EAAK,CAAa,EACpD,EAAgB,EAAe,EAAqB,GAAI,eAAe,EAC7E,GAAI,EAAqB,SAAW,GAAK,EAAc,MAAQ,GAC9D,MAAU,MAAM,yBAAyB,EAE1C,IAAM,EAAwB,EAAW,EAAK,CAAa,EAC3D,GAAI,EAAsB,SAAW,EACpC,MAAU,MAAM,sDAAsD,EAEvE,IAAM,EAAe,EAAe,EAAsB,GAAI,cAAc,EACtE,EAAW,EAAe,EAAsB,GAAI,UAAU,EACpE,GAAI,EAAS,MAAQ,EACpB,MAAU,MAAM,gCAAgC,EAEjD,IAAM,EAAkB,EAAuB,EAAa,KAAK,EACjE,GAAI,IAAoB,EAAK,kBAC5B,MAAO,CAAE,IAAK,IAAI,WAAW,CAAG,EAAG,iBAAgB,iBAAgB,EAEpE,IAAM,EAAgB,EAAS,MACzB,EAAgB,EAAqB,CAAa,EACxD,GAAI,EAAc,OAAS,GAAK,EAAc,OAAS,EACtD,MAAU,MAAM,6BAA6B,EAE9C,IAAM,EAAe,EAAe,EAAc,GAAI,cAAc,EAC9D,EAAqB,EAAe,EAAc,GAAI,oBAAoB,EAC1E,EAAiB,EAAe,EAAc,GAAI,gBAAgB,EAClE,EAAsB,EAAc,GAC1C,GAAI,IAAwB,IAAA,IAAa,EAAoB,MAAQ,IACpE,MAAU,MAAM,6BAA6B,EAE9C,IAAM,EAA6B,EAAW,EAAe,CAAkB,EACzE,EAAwB,EAC7B,EAAe,EAA2B,GAAI,wBAAwB,CAAC,CAAC,KACzE,EACM,EAA+B,EAA2B,GAC1D,EAAkB,EAAc,MACrC,EAAa,MAAQ,EAAa,aAClC,EAAa,GACd,EACM,EAAqB,GAA4B,CAAe,EACtE,MAAO,CACN,IAAK,IAAI,WAAW,CAAG,EACvB,iBACA,kBACA,kBACA,YAAa,EAAmB,YAChC,wBACA,uBAAwB,GACvB,EACA,IAAiC,IAAA,GAC9B,IAAA,GACA,EAAc,MACd,EAA6B,MAAQ,EAA6B,aAClE,EAA6B,GAC9B,CACH,EACA,eAAgB,EAAsB,CAAc,EACpD,WAAY,EAAmB,WAC/B,UAAW,EAAmB,UAC9B,GAAI,EAAmB,QAAU,IAAA,GAAY,CAAC,EAAI,CAAE,MAAO,EAAmB,KAAM,EACpF,GAAI,GAAqB,MAAQ,IAC9B,CACA,aAAc,GAA0B,EAAe,CAAmB,CAC3E,EACC,CAAC,CACL,CACD,CAiBA,SAAgB,EAAqB,EAAiC,CACrE,OAAO,EAAqB,EAAU,gBAAiB,CAAG,CAAC,CAC5D,CA6BA,eAAsB,GACrB,EACgC,CAChC,IAAM,EAAoB,MAAM,EAAqB,EAAM,iBAAiB,EACtE,EAAqB,GAAsB,EAAM,gBAAgB,EACjE,EAAa,EAAM,YAAc,IAAI,KACrC,EAAgB,EAAM,eAAiB,QACvC,EAA0B,CAAC,EACjC,IAAK,IAAM,KAAY,EAAM,UAAW,CACvC,IAAM,EAAc,MAAM,EAAqB,EAAS,WAAW,EAC7D,EAAS,MAAM,EAAqB,EAAS,iBAAiB,EACpE,EAAU,KAAK,MAAM,GAAqB,EAAa,EAAQ,EAAU,CAAa,CAAC,CACxF,CAKA,IAAM,EAAmC,CACxC,EAAyB,EAAG,MALE,EAC9B,QACA,EAA6B,EAAkB,uBAAuB,CACvE,CAE6C,EAC5C,EAAK,CAAU,EACf,EAAS,CAAS,CACnB,EACI,EAAM,QAAU,IAAA,IACnB,EAAmB,KAClB,EACC,EACA,EAAS,CACR,EAAS,CAAC,EAAiB,EAAK,SAAS,EAAG,EAAY,EAAY,EAAM,KAAK,CAAC,CAAC,CAAC,CACnF,CAAC,CACF,CACD,EAED,IAAM,EAAe,EAAS,CAAkB,EAC1C,EAAY,MAAM,GAAU,EAAM,iBAAkB,EAAoB,CAAY,EACpF,EACL,EAAM,uBAAyB,IAAA,GAC5B,CAAC,EACD,MAAM,QAAQ,IAAI,EAAM,qBAAqB,IAAI,CAAoB,CAAC,EACpE,EAAoC,CACzC,EACA,GAA0B,CAAkB,EAC5C,EAAU,CAAS,CACpB,EACI,EAAqB,OAAS,GACjC,EAAoB,KACnB,EAAgB,EAAG,EAAY,EAAqB,IAAK,GAAgB,EAAY,GAAG,CAAC,CAAC,CAC3F,EAED,IAAM,EAAgB,EAAS,CAAmB,EAC5C,EAAM,EAAS,CACpB,EAAI,GAAM,WAAW,GAAG,CAAI,CAAC,EAC7B,EACC,EACA,EAAS,CAAC,EAAiB,EAAK,iBAAiB,EAAG,EAAY,CAAa,CAAC,CAAC,CAChF,CACD,CAAC,EACD,MAAO,CACN,MACA,IAAK,EAAU,gBAAiB,CAAG,EACnC,OAAQ,EAAa,CAAG,CACzB,CACD,CAQA,eAAsB,EACrB,EACA,EACoC,CACpC,IAAI,EACJ,GAAI,CACH,EAAS,EAAsB,CAAQ,CACxC,MAAQ,CACP,OAAO,EACN,oBACA,2CACD,CACD,CACA,GACC,EAAO,kBAAoB,IAAA,IAC3B,EAAO,wBAA0B,IAAA,IACjC,EAAO,iBAAmB,IAAA,GAE1B,OAAO,EAAgC,oBAAqB,6BAA6B,EAE1F,IAAI,EACJ,GAAI,CACH,EAAS,MAAM,EAAqB,CAAiB,CACtD,MAAQ,CACP,OAAO,EACN,oBACA,4CACD,CACD,CACA,IAAI,EACJ,GAAI,CACH,EAAiB,MAAM,GACtB,EAAO,sBACP,IAAA,GACA,EAAO,sBACP,EAAO,uBACP,EAAO,wBACP,EAAO,eACP,EAAO,eACR,CACD,MAAQ,CACP,OAAO,EACN,oBACA,6CACD,CACD,CAaA,OAZK,EAAe,GAYb,EAAe,MACnB,CAAE,GAAI,GAAM,MAAO,CAAO,EAC1B,EACA,oBACA,yCACD,EAhBG,EAAe,OAAS,qBACpB,EACN,oBACA,6CACD,EAEM,EACN,oBACA,+DACD,CAQF,CAuBA,eAAsB,GACrB,EACsC,CACtC,IAAI,EACJ,GAAI,CACH,EAAiB,EAAsB,EAAM,QAAQ,CACtD,MAAQ,CACP,OAAO,EACN,oBACA,2CACD,CACD,CACA,GAAI,EAAe,iBAAmB,aACrC,OAAO,EACN,0BACA,2BAA2B,EAAe,gBAC3C,EAED,IAAI,EACJ,GAAI,CACH,EAAS,MAAM,EAAqB,EAAM,iBAAiB,CAC5D,MAAQ,CACP,OAAO,EACN,oBACA,uCACD,CACD,CACA,IAAI,EACJ,GAAI,CACH,EACC,EAAM,sBACL,MAAM,GACN,EAAe,aACf,EAAe,WAChB,GACA,EAAe,eAAe,IAC9B,EAAM,iBACR,MAAQ,CACP,OAAO,EACN,oBACA,+CACD,CACD,CACA,IAAI,EACJ,GAAI,CACH,EAAS,MAAM,EAAqB,CAAiB,CACtD,MAAQ,CACP,OAAO,EACN,oBACA,+CACD,CACD,CACA,IAAM,EAAY,MAAM,EAAmB,EAAgB,CAAM,EACjE,GAAI,CAAC,EAAU,GACd,OAAO,EAAkC,EAAU,KAAM,EAAU,OAAO,EAE3E,IAAI,EAGJ,GAAI,CACH,EAAmB,MAAM,GAA+B,EAAe,YAAa,CAAM,CAC3F,MAAQ,CACP,OAAO,EACN,oBACA,+CACD,CACD,CACA,GAAI,CAAC,EAAiB,GACrB,OAAO,EAER,GAAI,CAAC,EAAsB,EAAQ,CAAM,EAAG,CAC3C,IAAM,EAAmC,EAAM,mCAAqC,GACpF,GAAI,CAAC,GAAoC,CAAC,GAA6B,EAAQ,CAAM,EACpF,OAAO,EACN,0BACA,wEACD,EASD,GAAI,EAAC,MAPe,GAAuB,CAC1C,KAAM,EAAO,IACb,cAAe,EACZ,GAAgC,EAAe,aAAc,EAAQ,CAAM,EAC3E,CAAC,EACJ,MAAO,CAAC,EAAO,GAAG,CACnB,CAAC,EAAA,CACU,GACV,OAAO,EACN,0BACA,oDACD,EAED,GAAI,EAAO,mBAAqB,IAAA,IAAa,CAAC,EAAO,iBAAiB,SAAS,aAAa,EAC3F,OAAO,EACN,uBACA,gDACD,CAEF,CACA,IAAM,EAAK,EAAM,IAAM,IAAI,KACrB,EAAO,EAAM,aAAe,EAClC,GACC,EAAe,aAAe,IAAA,IAC9B,EAAe,WAAW,QAAQ,EAAI,EAAO,EAAG,QAAQ,EAExD,OAAO,EACN,iBACA,uDACD,EAED,IAAK,IAAM,KAAY,EAAe,WAAa,CAAC,EAAG,CACtD,IAAI,EACJ,GAAI,CACH,EAAW,MAAM,EAChB,EAAS,OAAO,iBAChB,EACA,EAAS,OAAO,eACjB,CACD,MAAQ,CACP,OAAO,EACN,oBACA,oDACD,CACD,CACA,GACC,EAAS,OAAO,oBAAsB,EAAS,mBAC/C,EAAS,OAAO,mBAAqB,EAAS,iBAE9C,OAAO,EACN,kBACA,wDACD,EAED,GACC,EAAS,WAAW,QAAQ,EAAI,EAAO,EAAG,QAAQ,GACjD,EAAS,aAAe,IAAA,IAAa,EAAS,WAAW,QAAQ,EAAI,EAAO,EAAG,QAAQ,EAExF,OAAO,EACN,iBACA,8CACD,EAED,GACC,EAAe,aAAe,IAAA,IAC9B,EAAS,aAAe,IAAA,IACxB,EAAe,WAAW,QAAQ,EAAI,EAAO,EAAS,WAAW,QAAQ,EAEzE,OAAO,EACN,iBACA,mDACD,CAEF,CACA,GAAI,GAA0C,EAAe,WAAa,CAAC,CAAC,EAC3E,OAAO,EACN,oBACA,yEACD,EAED,GAAI,EAAM,UAAY,IAAA,GAAW,CAChC,IAAI,EACJ,GAAI,CACH,EAAU,GAAqB,EAAM,OAAO,CAC7C,MAAQ,CACP,OAAO,EACN,mBACA,iCACD,CACD,CACA,GAAI,EAAQ,QAAU,IAAA,IAAa,EAAQ,QAAU,EAAe,MACnE,OAAO,EACN,iBACA,kDACD,EAED,IAAM,EAAa,IAAI,IAAI,EAAQ,SAAS,IAAK,GAAU,EAAgB,CAAK,CAAC,CAAC,EAC5E,EAAc,IAAI,KACtB,EAAe,WAAa,CAAC,EAAA,CAAG,IAAK,GAAa,EAAgB,EAAS,MAAM,CAAC,CACpF,EACA,IAAK,IAAM,KAAY,EAAe,WAAa,CAAC,EACnD,GAAI,CAAC,EAAW,IAAI,EAAgB,EAAS,MAAM,CAAC,EACnD,OAAO,EACN,mBACA,wDACD,EAGF,IAAK,IAAM,KAAa,EACvB,GAAI,CAAC,EAAY,IAAI,CAAS,EAC7B,OAAO,EACN,mBACA,qDACD,CAGH,CACA,MAAO,CAAE,GAAI,GAAM,MAAO,CAAe,CAC1C,CAGA,SAAS,EACR,EACA,EACoF,CAMpF,MAAO,CAAE,GAAI,GAAO,MAAA,CAJnB,GAAI,GACJ,OACA,SAEuB,EAAG,OAAM,SAAQ,CAC1C,CAGA,SAAS,EACR,EAUA,EAaC,CAMD,MAAO,CAAE,GAAI,GAAO,MAAA,CAJnB,GAAI,GACJ,OACA,SAEuB,EAAG,OAAM,SAAQ,CAC1C,CAGA,SAAS,EACR,EACqB,CACrB,GAAI,OAAO,GAAa,SACvB,OAAO,EAAqB,CAAQ,EAErC,GAAI,aAAoB,WACvB,OAAO,EAAqB,CAAQ,EAErC,GAAI,EAAgC,CAAQ,EAC3C,OAAO,EAAqB,IAAI,WAAW,EAAS,GAAG,CAAC,EAEzD,MAAU,MAAM,kCAAkC,CACnD,CAGA,SAAS,GAAqB,EAA+C,CAC5E,GAAI,OAAO,GAAY,SACtB,OAAO,EAAoB,CAAO,EAEnC,GAAI,aAAmB,WACtB,OAAO,EAAoB,CAAO,EAEnC,GAAI,GAA+B,CAAO,EACzC,OAAO,EAAoB,IAAI,WAAW,EAAQ,GAAG,CAAC,EAEvD,MAAU,MAAM,iCAAiC,CAClD,CAEA,SAAS,GAA4B,EAKnC,CACD,IAAM,EAAuB,EAAqB,CAAe,EACjE,GAAI,EAAqB,OAAS,GAAK,EAAqB,OAAS,EACpE,MAAU,MAAM,6BAA6B,EAE9C,IAAI,EAAQ,EACZ,GAAI,EAAqB,EAAM,EAAE,MAAQ,IAAM,CAE9C,IAAM,EAAgB,EAAW,EADV,EAAe,EAAqB,GAAQ,SACJ,CAAC,EAC1D,EAAiB,EAAe,EAAc,GAAI,SAAS,EACjE,GAAI,EAAc,SAAW,GAAK,EAAe,MAAQ,EACxD,MAAU,MAAM,0BAA0B,EAE3C,GAAI,EAA+B,EAAe,MAAO,uBAAuB,IAAM,EACrF,MAAU,MAAM,mCAAmC,EAEpD,GAAS,CACV,CAEA,IAAM,EAAc,GAAqB,EADd,EAAe,EAAqB,GAAQ,aACI,CAAC,EAC5E,GAAS,EACT,IAAM,EAAoB,EAAe,EAAqB,GAAQ,YAAY,EAC5E,EAAmB,EAAe,EAAqB,EAAQ,GAAI,WAAW,EACpF,GAAI,EAAiB,MAAQ,GAC5B,MAAU,MAAM,6BAA6B,EAE9C,GAAI,EAAW,EAAiB,CAAgB,CAAC,CAAC,SAAW,EAC5D,MAAU,MAAM,6BAA6B,EAE9C,IAAM,EAAqB,EAAqB,EAAQ,GAIxD,GAHI,IAAuB,IAAA,IAAa,EAAmB,MAAQ,KAG/D,EAAqB,SAAW,EAAQ,GAAK,IAAuB,IAAA,GAAY,EAAI,GACvF,MAAU,MAAM,6BAA6B,EAE9C,IAAM,EACL,IAAuB,IAAA,GACpB,IAAA,GACA,EAA6B,EAAiB,CAAkB,EAC9D,EAAkB,EAAW,EAAiB,CAAgB,CAAC,CAAC,IAAK,GAC1E,GAAoB,EAAiB,CAAc,CACpD,EAEA,OADA,GAAgC,CAAe,EACxC,CACN,cACA,WAAY,EAAU,CAAiB,EACvC,UAAW,EACX,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,OAAM,CACxC,CACD,CAGA,eAAe,GACd,EACA,EACyC,CACrC,SAAiB,IAAA,IAAa,IAAgB,IAAA,IAGlD,KAAK,IAAM,KAAe,EACzB,GAAI,MAAM,EAAuB,EAAa,CAAW,EACxD,OAAO,CAAA,CAIV,CAGA,eAAe,GACd,EACA,EAC+F,CAO/F,OANI,IAAgB,IAAA,IAGhB,MAAM,EAAuB,EAAa,CAAM,EAC5C,CAAE,GAAI,EAAK,EAEZ,EAAY,OAAS,SACzB,EACA,wBACA,sEACD,EACC,EACA,wBACA,4EACD,CACH,CAGA,eAAe,EACd,EACA,EACmB,CAOnB,OANI,EAAY,OAAS,SACjB,GAA0B,EAAY,KAAM,EAAY,OAAO,EAEzC,EAC7B,MAAM,EAAY,QAAS,EAA6B,EAAY,uBAAuB,CAAC,CAElE,IAAM,EAAY,UAC9C,CAGA,SAAS,EAAsB,EAAyB,EAAmC,CAC1F,OACC,EAAK,kBAAoB,EAAM,iBAC/B,EAA0B,EAAK,OAAQ,EAAM,MAAM,GACnD,EAA0B,EAAK,QAAS,EAAM,OAAO,GACrD,EAAK,wBAAwB,SAAW,EAAM,wBAAwB,QACtE,EAAK,wBAAwB,OAC3B,EAAM,IAAU,IAAS,EAAM,wBAAwB,EACzD,CAEF,CAGA,SAAS,GACR,EACA,EACU,CAWV,MAPA,EAHI,CAAC,EAA0B,EAAO,OAAQ,EAAO,OAAO,GAI3D,EAAO,yBAA2B,IAAA,IAClC,EAAO,uBAAyB,IAAA,IAChC,EAAO,yBAA2B,EAAO,qBAK3C,CAGA,SAAS,GACR,EACA,EACA,EACwB,CACxB,GAAI,IAAiB,IAAA,GACpB,MAAO,CAAC,EAET,IAAM,EAA8B,CAAC,EACrC,IAAK,IAAM,KAAe,EACrB,EAAsB,EAAa,CAAM,GAAK,EAAsB,EAAa,CAAM,GAG3F,EAAc,KAAK,EAAY,GAAG,EAEnC,OAAO,CACR,CAGA,eAAe,EACd,EACA,EACA,EACsB,CACtB,IAAM,EAAmB,IAAkB,QAAU,EAAK,KAAO,EAAK,OAChE,EAAS,MAAM,EAAsB,EAAkB,EAAQ,EAAY,eAAe,EAChG,OAAO,EAAS,CACf,EAAS,CAAC,EAAiB,CAAgB,EAAG,EAAU,CAAC,CAAC,EAC1D,EAAY,EAAW,EAAO,iBAAiB,CAAC,EAChD,EAAY,EAAW,EAAO,gBAAgB,CAAC,EAC/C,EAAQ,EAAW,EAAO,eAAe,CAAC,CAC3C,CAAC,CACF,CAGA,eAAe,EACd,EACA,EACA,EAC4B,CAC5B,IAAM,EAAgB,GAAyB,CAAgB,EAC/D,MAAO,CACN,mBACA,kBAAmB,EAAsB,CAAgB,EACzD,kBAAmB,EAAM,MAAM,EAAY,EAAe,EAAW,EAAO,QAAQ,MAAM,CAAC,CAAC,EAC5F,iBAAkB,EACjB,MAAM,EACL,EACA,EAA6B,EAAO,uBAAuB,CAC5D,CACD,EACA,iBACD,CACD,CAGA,eAAe,EAAY,EAA8B,EAAwC,CAChG,OAAO,IAAI,WAAW,MAAM,EAAU,CAAC,CAAC,OAAO,OAAO,EAAW,EAAc,CAAK,CAAC,CAAC,CACvF,CAGA,eAAe,GACd,EACA,EACA,EACA,EACsB,CAGtB,OAAO,EAAS,CACf,MAHoB,EAAiB,EAAa,EAAQ,CAAa,EACrD,GAAqB,CAG9B,EACT,EAAK,EAAM,YAAc,IAAI,IAAM,EACnC,GAAI,EAAM,aAAe,IAAA,GAAY,CAAC,EAAI,CAAC,EAAgB,EAAG,EAAK,EAAM,UAAU,CAAC,CAAC,CACtF,CAAC,CACF,CAGA,SAAS,GAAqB,EAAkD,CAC/E,OAAQ,EAAM,WAAd,CACC,IAAK,OACJ,OAAO,EAAI,IAAM,IAAI,UAAY,EAClC,IAAK,UACJ,OAAO,EAAI,IAAM,IAAI,UAAY,EAClC,IAAK,UAAW,CACf,IAAM,EAA8B,CAAC,EAAK,EAAM,WAAa,EAAM,YAAc,IAAI,IAAM,CAAC,EAM5F,OALI,EAAM,uBAAyB,IAAA,IAClC,EAAc,KACb,EAAgB,EAAG,EAAI,GAAM,WAAW,GAAG,EAAM,oBAAoB,CAAC,CAAC,CACxE,EAEM,EAAI,IAAM,EAAY,CAAa,CAAC,CAC5C,CACD,CACD,CAGA,SAAS,EAAqB,EAAkD,CAI/E,OAHI,GAA0B,CAAM,EAC5B,EAAoB,IAAI,WAAW,EAAO,GAAG,CAAC,EAE/C,EAA2B,CAAM,CACzC,CAGA,SAAS,GAA0B,EAA0D,CAC5F,OAAO,OAAO,GAAU,UAAY,4BAA6B,CAClE,CAGA,SAAS,EAAgB,EAAmC,CAC3D,IAAM,EAAO,EAAgB,EAAK,CAAE,SAAA,EAAgC,CAAC,EACrE,GAAI,EAAK,MAAQ,GAChB,MAAU,MAAM,0BAA0B,EAE3C,IAAM,EAAW,EAAW,EAAK,CAAI,EACrC,GAAI,EAAS,SAAW,EACvB,MAAU,MACT,oFACD,EAED,IAAM,EAAgB,EAAe,EAAS,GAAI,eAAe,EACjE,GAAI,EAAc,MAAQ,GACzB,MAAU,MAAM,iCAAiC,EAElD,IAAM,EAAoB,EAAW,EAAK,CAAa,EACvD,GAAI,EAAkB,OAAS,GAAK,EAAkB,OAAS,EAC9D,MAAU,MAAM,yBAAyB,EAG1C,IAAM,EAAmB,EADJ,EAAe,EAAkB,GAAI,mBACC,CAAC,CAAC,KAAK,EAClE,GAAI,EAAe,EAAS,GAAI,gBAAgB,CAAC,CAAC,MAAQ,EACzD,MAAU,MAAM,sCAAsC,EAEvD,GAAI,EAAe,EAAS,GAAI,eAAe,CAAC,CAAC,MAAQ,EACxD,MAAU,MAAM,qCAAqC,EAEtD,IAAM,EAAe,EAAe,EAAS,GAAI,cAAc,EAC/D,GAAI,EAAa,MAAQ,EACxB,MAAU,MAAM,+BAA+B,EAEhD,MAAO,CACN,mBACA,kBAAmB,EAAsB,CAAgB,EACzD,kBAAmB,EAAM,EAAe,EAAS,GAAI,gBAAgB,CAAC,CAAC,KAAK,EAC5E,iBAAkB,EAAM,EAAe,EAAS,GAAI,eAAe,CAAC,CAAC,KAAK,EAC1E,gBAAiB,EAAM,EAAa,KAAK,CAC1C,CACD,CAGA,SAAS,GAAoB,EAAoB,EAA+C,CAC/F,IAAM,EAAW,EAAW,EAAQ,CAAO,EAC3C,GAAI,EAAS,OAAS,GAAK,EAAS,OAAS,EAC5C,MAAU,MAAM,+BAA+B,EAEhD,IAAM,EAAS,EAAe,EAAS,GAAI,QAAQ,EAC7C,EAAa,EAAe,EAAS,GAAI,YAAY,EACrD,EAAa,EAAe,EAAS,GAAI,YAAY,EACvD,EAAS,EACP,EAAoB,EAAS,EAAO,EAAE,MAAQ,IAAO,EAAS,GAAU,IAAA,GAC1E,IAAsB,IAAA,KACzB,GAAqC,EAAQ,CAAiB,EAC9D,GAAU,GAEX,IAAM,EAAmB,EAAS,GAIlC,GAHI,IAAqB,IAAA,IAAa,EAAiB,MAAQ,KAG3D,EAAS,SAAW,GAAU,IAAqB,IAAA,GAAY,EAAI,GACtE,MAAU,MAAM,+BAA+B,EAEhD,IAAI,EACA,EACJ,GAAI,EAAW,MAAQ,IAAM,CAC5B,GAAI,EAAW,MAAM,SAAW,EAC/B,MAAU,MAAM,oCAAoC,EAErD,MAAO,CACN,OAAQ,EAAgB,EAAO,MAAM,EAAO,MAAQ,EAAO,aAAc,EAAO,GAAG,CAAC,EACpF,WAAY,OACZ,WAAY,EAAU,CAAU,EAChC,GAAI,IAAsB,IAAA,GACvB,CAAC,EACD,CACA,WAAY,EACX,EAAe,EAAW,EAAQ,CAAiB,CAAC,CAAC,GAAI,YAAY,CACtE,CACD,CACH,CACD,CACA,GAAI,EAAW,MAAQ,IAAM,CAC5B,IAAM,EAAc,EAAW,EAAQ,CAAU,EACjD,GAAI,EAAY,OAAS,GAAK,EAAY,OAAS,EAClD,MAAU,MAAM,mCAAmC,EAEpD,EAAY,EAAU,EAAe,EAAY,GAAI,gBAAgB,CAAC,EACtE,IAAM,EAAS,EAAY,GAC3B,GAAI,GAAQ,MAAQ,IAAM,CACzB,IAAM,EAAiB,EAAW,EAAQ,CAAM,EAC1C,EAAa,EAAe,EAAe,GAAI,kBAAkB,EACvE,GAAI,EAAe,SAAW,GAAK,EAAW,MAAQ,GACrD,MAAU,MAAM,sCAAsC,EAEvD,EAAuB,EACtB,EAAW,MACX,uBACD,CACD,MAAO,GAAI,IAAW,IAAA,GACrB,MAAU,MAAM,mCAAmC,CAErD,MAAO,GAAI,EAAW,MAAQ,IAC7B,MAAU,MAAM,oCAAoC,OAAO,EAAW,GAAG,GAAG,OACtE,GAAI,EAAW,MAAM,SAAW,EACtC,MAAU,MAAM,uCAAuC,EAExD,MAAO,CACN,OAAQ,EAAgB,EAAO,MAAM,EAAO,MAAQ,EAAO,aAAc,EAAO,GAAG,CAAC,EACpF,WAAY,EAAW,MAAQ,IAAO,UAAY,UAClD,WAAY,EAAU,CAAU,EAChC,GAAI,IAAsB,IAAA,GACvB,CAAC,EACD,CACA,WAAY,EACX,EAAe,EAAW,EAAQ,CAAiB,CAAC,CAAC,GAAI,YAAY,CACtE,CACD,EACF,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,WAAU,EAC/C,GAAI,IAAyB,IAAA,GAAY,CAAC,EAAI,CAAE,sBAAqB,CACtE,CACD,CAGA,SAAS,GAAqB,EAAoB,EAA4C,CAC7F,OAAQ,EAAQ,IAAhB,CACC,IAAK,KACJ,GAAI,EAAQ,MAAM,SAAW,EAC5B,MAAU,MAAM,yCAAyC,EAE1D,MAAO,CAAE,KAAM,YAAa,WAAY,EAAM,EAAQ,KAAK,CAAE,EAC9D,IAAK,KACJ,GAAI,EAAW,EAAQ,CAAO,CAAC,CAAC,SAAW,EAC1C,MAAU,MAAM,+CAA+C,EAEhE,MAAO,CACN,KAAM,SACN,KAAM,GACL,EACA,EAAe,EAAW,EAAQ,CAAO,CAAC,CAAC,GAAI,oBAAoB,CACpE,CACD,EACD,QACC,MAAU,MAAM,qCAAqC,OAAO,EAAQ,GAAG,GAAG,CAC5E,CACD,CAGA,SAAS,GAAmB,EAAoB,EAAiC,CAChF,GAAI,EAAQ,MAAQ,GACnB,MAAU,MAAM,2CAA2C,EAE5D,IAAM,EAA0C,CAAC,EAC3C,EAAoC,CAAC,EACrC,EAA+B,CAAC,EACtC,IAAK,IAAM,KAAc,EAAW,EAAQ,CAAO,EAAG,CACrD,IAAM,EAAM,GAA+B,EAAQ,CAAU,EAC7D,EAAK,KAAK,CAAG,EACb,IAAK,IAAM,KAAa,EAAI,WAC3B,EAAW,KAAK,CAAS,EACrB,EAAU,MAAQ,IAAA,IAAa,EAAO,EAAU,OAAS,IAAA,KAC5D,EAAO,EAAU,KAAO,EAAU,MAGrC,CACA,MAAO,CACN,OAAQ,EAAM,EAAO,MAAM,EAAQ,MAAQ,EAAQ,aAAc,EAAQ,GAAG,CAAC,EAC7E,OACA,aACA,QACD,CACD,CAGA,SAAS,GACR,EACA,EACkC,CAClC,IAAM,EAAoC,CAAC,EACrC,EAAoD,CAAC,EAC3D,IAAK,IAAM,KAAqB,EAAW,EAAQ,CAAU,EAAG,CAC/D,IAAM,EAAQ,EAAW,EAAQ,CAAiB,EAC5C,EAAM,EAAuB,EAAe,EAAM,GAAI,UAAU,CAAC,CAAC,KAAK,EACvE,EAAe,EAAe,EAAM,GAAI,YAAY,EACpD,EAAM,GAAwB,CAAG,EACjC,EAAQ,EAAa,EAAa,IAAK,EAAa,KAAK,EACzD,EACL,IAAQ,IAAA,GACL,CAAE,MAAK,SAAU,EAAa,IAAK,OAAM,EACzC,CAAE,MAAK,MAAK,SAAU,EAAa,IAAK,OAAM,EAClD,EAAW,KAAK,CAAS,EACrB,IAAQ,IAAA,IAAa,EAAO,KAAS,IAAA,KACxC,EAAO,GAAO,EAEhB,CACA,MAAO,CACN,OAAQ,EAAM,EAAO,MAAM,EAAW,MAAQ,EAAW,aAAc,EAAW,GAAG,CAAC,EACtF,aACA,QACD,CACD,CAGA,SAAS,GAA0B,EAAkB,EAA4B,CAChF,GAAI,EAAK,KAAK,SAAW,EAAM,KAAK,OACnC,MAAO,GAER,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAK,KAAK,OAAQ,GAAS,EAAG,CACzD,IAAM,EAAU,EAAK,KAAK,GACpB,EAAW,EAAM,KAAK,GAI5B,GAHI,IAAY,IAAA,IAAa,IAAa,IAAA,IAGtC,CAAC,GAAsC,EAAS,CAAQ,EAC3D,MAAO,EAET,CACA,MAAO,EACR,CAGA,SAAS,GACR,EACA,EACU,CACV,GAAI,EAAK,WAAW,SAAW,EAAM,WAAW,OAC/C,MAAO,GAER,IAAM,EAAc,MAAM,EAAM,WAAW,MAAM,CAAC,CAAC,KAAK,EAAK,EAC7D,IAAK,IAAM,KAAiB,EAAK,WAAY,CAC5C,IAAI,EAAQ,GACZ,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,WAAW,OAAQ,GAAS,EAAG,CAChE,IAAM,EAAiB,EAAM,WAAW,GACpC,SAAmB,IAAA,IAAa,EAAQ,KAGvC,GAA8B,EAAe,CAAc,EAIhE,CADA,EAAQ,GAAS,GACjB,EAAQ,GACR,KADQ,CAET,CACA,GAAI,CAAC,EACJ,MAAO,EAET,CACA,MAAO,EACR,CAGA,SAAS,GACR,EACA,EACU,CACV,GAAI,EAAK,MAAQ,EAAM,IACtB,MAAO,GAER,GAAI,EAAyB,EAAK,QAAQ,GAAK,EAAyB,EAAM,QAAQ,EAAG,CACxF,IAAM,EAAe,EAA6B,EAAK,KAAK,EACtD,EAAgB,EAA6B,EAAM,KAAK,EAI9D,OAHI,IAAiB,IAAA,IAAa,IAAkB,IAAA,GAC5C,GAED,IAAiB,CACzB,CACA,OAAO,EAAK,WAAa,EAAM,UAAY,EAAK,QAAU,EAAM,KACjE,CAGA,SAAS,EAAyB,EAAsB,CACvD,OAAO,IAAQ,IAAQ,IAAQ,EAChC,CAGA,SAAS,EAA6B,EAAmC,CACxE,IAAM,EAAa,EAAM,UAAU,MAAM,EACrC,uBAAmB,KAAK,CAAU,EAGtC,OAAO,EAAW,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,QAAS,GAAG,CAC5D,CAGA,SAAS,GAAwB,EAAyC,CACzE,OAAQ,EAAR,CACC,KAAK,EAAK,WACT,MAAO,aACR,KAAK,EAAK,QACT,MAAO,UACR,KAAK,EAAK,aACT,MAAO,eACR,KAAK,EAAK,YACT,MAAO,UACR,KAAK,EAAK,aACT,MAAO,WACR,KAAK,EAAK,oBACT,MAAO,QACR,KAAK,EAAK,cACT,MAAO,SACR,KAAK,EAAK,iBACT,MAAO,eACR,KAAK,EAAK,uBACT,MAAO,qBACR,KAAK,EAAK,MACT,MAAO,QACR,KAAK,EAAK,UACT,MAAO,YACR,KAAK,EAAK,aACT,MAAO,eACR,QACC,MACF,CACD,CAGA,SAAS,EAA6B,EAAoB,EAAyC,CAClG,IAAM,EAAqB,EAAW,EAAQ,CAAO,EAC/C,EAAqB,EAAe,EAAmB,GAAI,YAAY,EAC7E,GAAI,EAAmB,SAAW,GAAK,EAAmB,MAAQ,GACjE,MAAU,MAAM,2BAA2B,EAE5C,IAAM,EAAW,IAAI,IACjB,EACJ,IAAK,IAAM,KAAa,EAAW,EAAQ,CAAkB,EAAG,CAC/D,IAAM,EAAQ,EAAW,EAAQ,CAAS,EAI1C,GAHI,EAAM,OAAS,GAAK,EAAM,OAAS,GAGnC,EAAM,SAAW,GAAK,EAAM,EAAE,EAAE,MAAQ,EAC3C,MAAU,MAAM,0BAA0B,EAE3C,IAAM,EAAM,EAAuB,EAAe,EAAM,GAAI,eAAe,CAAC,CAAC,KAAK,EAClF,GAAI,EAAS,IAAI,CAAG,EACnB,MAAU,MAAM,iCAAiC,GAAK,EAEvD,EAAS,IAAI,CAAG,EAChB,IAAM,EAAY,EAAe,EAAM,EAAM,OAAS,GAAI,WAAW,EACrE,GAAI,EAAU,MAAQ,EACrB,MAAU,MAAM,4CAA4C,EAE7D,GAAI,IAAQ,EAAK,UAChB,SAED,IAAM,EAAe,EAAgB,EAAU,MAAO,CAAE,SAAA,EAAgC,CAAC,EACzF,GAAI,EAAa,MAAQ,EACxB,MAAU,MAAM,kDAAkD,EAEnE,EAAQ,EAAM,EAAa,KAAK,CACjC,CACA,OAAO,CACR,CAGA,SAAS,GACR,EACA,EAC+B,CAC/B,IAAM,EAAoC,CAAC,EACvC,EAAS,EAAQ,MACrB,KAAO,EAAS,EAAQ,KAAK,CAC5B,IAAM,EAAQ,EAAY,EAAQ,CAAM,EACxC,EAAa,KAAK,EAAoB,EAAO,MAAM,EAAQ,EAAM,GAAG,CAAC,CAAC,EACtE,EAAS,EAAM,GAChB,CACA,OAAO,CACR,CAGA,SAAS,EAA6B,EAAiC,CAEtE,IAAM,EAAmB,EADb,EAAW,EAAS,EAAY,CAAO,CACT,CAAC,CAAC,GAAI,6BAA6B,EAC7E,GAAI,EAAiB,MAAQ,EAC5B,MAAU,MAAM,0CAA0C,EAE3D,OAAO,EAAiB,MAAM,MAAM,CAAC,CACtC,CAGA,SAAS,GAA2B,EAA8C,CACjF,OAAQ,EAAR,CACC,IAAK,GACJ,MAAO,aACR,IAAK,GACJ,MAAO,mBACR,IAAK,GACJ,MAAO,gBACR,IAAK,GACJ,MAAO,WACR,IAAK,GACJ,MAAO,cACR,IAAK,GACJ,MAAO,eACR,QACC,MAAU,MAAM,0CAA0C,OAAO,CAAI,GAAG,CAC1E,CACD,CAEA,SAAS,GACR,EAC8D,CAC9D,MAAO,QAAS,GAAW,EAAQ,eAAe,UACnD,CAEA,SAAS,EACR,EACgE,CAChE,MAAO,QAAS,GAAY,EAAS,eAAe,UACrD,CAEA,SAAS,GAAgC,EAAsD,CAC9F,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAY,EAAW,CACjC,IAAM,EAAM,EAAgB,EAAS,MAAM,EAC3C,GAAI,EAAK,IAAI,CAAG,EACf,MAAU,MAAM,gCAAgC,EAEjD,EAAK,IAAI,CAAG,CACb,CACD,CAEA,SAAS,GACR,EACU,CACV,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAY,EAAW,CACjC,IAAM,EAAS,GAAa,EAAS,OAAO,eAAe,EAC3D,GAAI,EAAK,IAAI,CAAM,EAClB,MAAO,GAER,EAAK,IAAI,CAAM,CAChB,CACA,MAAO,EACR,CAEA,SAAS,GAA0B,EAAoB,EAA2B,CACjF,IAAM,EAAW,EAAW,EAAQ,CAAO,EACrC,EAAgB,EAAe,EAAS,GAAI,eAAe,EACjE,GAAI,EAAS,SAAW,IAAM,EAAc,IAAM,MAAU,IAC3D,MAAU,MAAM,iDAAiD,CAEnE,CAEA,SAAS,GAA8B,EAAoB,EAA2B,CACrF,IAAM,EAAkB,EAAW,EAAQ,CAAO,EAC5C,EAAoB,EAAe,EAAgB,GAAI,mBAAmB,EAChF,GAAI,EAAgB,SAAW,GAAK,EAAkB,MAAQ,GAC7D,MAAU,MAAM,mDAAmD,EAEpE,IAAM,EAAoB,EAAW,EAAQ,CAAiB,EAC9D,GACC,EAAkB,OAAS,GAC3B,EAAkB,OAAS,GAC3B,EAAkB,EAAE,EAAE,MAAQ,IAC7B,EAAkB,KAAO,IAAA,IAAa,EAAkB,EAAE,EAAE,MAAQ,IAErE,MAAU,MAAM,6BAA6B,EAE9C,IAAM,EAAqB,EAAe,EAAkB,GAAI,oBAAoB,EAC9E,EAAiB,EAAe,EAAkB,GAAI,WAAW,EACjE,EAAe,EAAkB,GAGvC,GAFA,GAAiC,EAAQ,EAAoB,6BAA6B,EAC1F,EAAsB,CAAc,EAChC,IAAiB,IAAA,GAAW,CAC/B,IAAM,EAAsB,EAAW,EAAQ,CAAY,EAC3D,GAAI,EAAoB,SAAW,GAAK,EAAoB,EAAE,EAAE,MAAQ,GACvE,MAAU,MAAM,0DAA0D,CAE5E,CACD,CAEA,SAAS,GAAqC,EAAoB,EAA2B,CAC5F,IAAM,EAAW,EAAW,EAAQ,CAAO,EACrC,EAAa,EAAe,EAAS,GAAI,YAAY,EAC3D,GAAI,EAAS,SAAW,GAAM,EAAW,MAAQ,IAAQ,EAAW,MAAQ,GAC3E,MAAU,MAAM,6CAA6C,CAE/D,CAEA,SAAS,GACR,EACA,EACA,EACO,CACP,IAAM,EAAW,EAAW,EAAQ,CAAO,EAC3C,GACC,EAAQ,MAAQ,IAChB,EAAS,OAAS,GAClB,EAAS,OAAS,GAClB,EAAS,EAAE,EAAE,MAAQ,EAErB,MAAU,MAAM,GAAG,EAAM,uCAAuC,EAEjE,EAAuB,EAAe,EAAS,GAAI,GAAG,EAAM,KAAK,CAAC,CAAC,KAAK,CACzE,CAEA,SAAS,GAAa,EAAuB,CAC5C,OAAO,EAAM,YAAY,CAC1B,CAGA,SAAS,GAAyB,EAAgC,CACjE,OAAQ,EAAR,CACC,KAAK,EAAK,KACT,MAAO,QACR,KAAK,EAAK,OACT,MAAO,UACR,QACC,MAAU,MAAM,wCAAwC,GAAK,CAC/D,CACD,CAGA,SAAS,EAAgB,EAAkC,CAC1D,MAAO,CACN,EAAO,iBACP,EAAO,kBACP,EAAO,iBACP,EAAO,eACR,CAAC,CAAC,KAAK,GAAG,CACX"}
@@ -0,0 +1,168 @@
1
+ import { Result } from "../result/result.js";
2
+ import { ParsedCertificate } from "../x509/parse.js";
3
+ import { CertificateRevocationListMaterial, CheckCertificateRevocationAgainstCrlErrorCode, CheckCertificateRevocationAgainstCrlFailure, CheckCertificateRevocationAgainstCrlFailureDetails, CheckCertificateRevocationAgainstCrlGoodValue, CheckCertificateRevocationAgainstCrlInput, CheckCertificateRevocationAgainstCrlResult, CheckCertificateRevocationAgainstCrlRevokedValue, CheckCertificateRevocationAgainstCrlValue, CreateCertificateRevocationListInput, CrlApplicabilityFailureReason, CrlCertificateSource, CrlSource, ParsedCertificateRevocationList, ParsedRevokedCertificate, RevocationReason, RevokedCertificateInput, ValidateCertificateRevocationListFailure, ValidateCertificateRevocationListInput, ValidateCertificateRevocationListResult, VerifyCertificateRevocationListFailure, VerifyCertificateRevocationListResult, checkCertificateRevocationAgainstCrl, createCertificateRevocationList, isCertificateRevoked, parseCertificateRevocationListDer, parseCertificateRevocationListPem, validateCertificateRevocationList, verifyCertificateRevocationList } from "./crl.js";
4
+ import { CreateOcspRequestInput, CreateOcspRequestItemInput, CreateOcspResponseInput, CreateOcspSingleResponseInput, OcspCertStatus, OcspCertificateSource, OcspHashAlgorithm, OcspRequestMaterial, OcspRequestSource, OcspResponseMaterial, OcspResponseStatus, ParsedOcspCertId, ParsedOcspRequest, ParsedOcspResponderId, ParsedOcspResponse, ParsedOcspSingleResponse, ValidateOcspResponseFailure, ValidateOcspResponseInput, ValidateOcspResponseResult, VerifyOcspResponseFailure, VerifyOcspResponseResult, createOcspRequest, createOcspResponse, parseOcspRequestDer, parseOcspRequestPem, parseOcspResponseDer, parseOcspResponsePem, validateOcspResponse, verifyOcspResponse } from "./ocsp.js";
5
+
6
+ //#region src/revocation/revocation.d.ts
7
+ /** Unified revocation outcome across CRL and OCSP evidence. */
8
+ type RevocationStatus = "good" | "revoked" | "unknown";
9
+ /** Which revocation mechanism produced the evidence. */
10
+ type RevocationEvidenceKind = "crl" | "ocsp";
11
+ /** PEM string, DER bytes, or already-parsed certificate. */
12
+ type RevocationCertificateSource = string | Uint8Array | ParsedCertificate;
13
+ /** Where the OCSP responder URI came from. */
14
+ type OcspResponderSource = "configured" | "authorityInfoAccess";
15
+ /** PEM or DER bytes of a pre-configured OCSP responder certificate. */
16
+ type ConfiguredOcspResponderCertificate = string | Uint8Array;
17
+ /** A manually-configured OCSP responder endpoint. */
18
+ interface ConfiguredOcspResponder {
19
+ /** OCSP responder URI (typically `http://...`). */
20
+ readonly uri: string;
21
+ /** Known responder certificate — skips embedded-certificate discovery. */
22
+ readonly responderCertificate?: ConfiguredOcspResponderCertificate;
23
+ }
24
+ /** One candidate OCSP responder resolved by {@linkcode resolveOcspResponderCandidates}. */
25
+ interface OcspResponderCandidate {
26
+ /** Whether this candidate came from configuration or the certificate's AIA extension. */
27
+ readonly source: OcspResponderSource;
28
+ /** OCSP responder URI. */
29
+ readonly uri: string;
30
+ /** Pre-known responder certificate, if available. */
31
+ readonly responderCertificate?: ConfiguredOcspResponderCertificate;
32
+ }
33
+ /** Input for {@linkcode resolveOcspResponderCandidates}. */
34
+ interface ResolveOcspResponderCandidatesInput {
35
+ /** Certificate whose AIA extension will be inspected for OCSP URIs. */
36
+ readonly certificate: RevocationCertificateSource;
37
+ /** Manually-configured responders — checked before AIA-derived ones. */
38
+ readonly configuredResponders?: readonly ConfiguredOcspResponder[];
39
+ }
40
+ /** CRL-based revocation evidence for {@linkcode CheckCertificateRevocationInput.evidence}. */
41
+ interface RevocationCrlEvidenceInput {
42
+ /** Discriminator for the CRL evidence variant. */
43
+ readonly kind: "crl";
44
+ /** Complete (base) CRL. */
45
+ readonly crl: CrlSource;
46
+ /** Optional delta CRL for more recent revocation information. */
47
+ readonly deltaCrl?: CrlSource;
48
+ }
49
+ /** OCSP-based revocation evidence for {@linkcode CheckCertificateRevocationInput.evidence}. */
50
+ interface RevocationOcspEvidenceInput {
51
+ /** Discriminator for the OCSP evidence variant. */
52
+ readonly kind: "ocsp";
53
+ /** OCSP response to validate. */
54
+ readonly response: string | Uint8Array | ParsedOcspResponse;
55
+ /** Original OCSP request — enables nonce and coverage checks. */
56
+ readonly request?: OcspRequestSource;
57
+ /** Explicit responder certificate — overrides embedded certificate discovery. */
58
+ readonly responderCertificate?: OcspCertificateSource;
59
+ }
60
+ /** Discriminated union of CRL and OCSP evidence inputs. */
61
+ type RevocationEvidenceInput = RevocationCrlEvidenceInput | RevocationOcspEvidenceInput;
62
+ /** Input for {@linkcode checkCertificateRevocation}. */
63
+ interface CheckCertificateRevocationInput {
64
+ /** Certificate whose revocation status to determine. */
65
+ readonly certificate: RevocationCertificateSource;
66
+ /** Issuer of `certificate`. */
67
+ readonly issuerCertificate: RevocationCertificateSource;
68
+ /** CRL and/or OCSP evidence to evaluate. Returns `unknown` if empty. */
69
+ readonly evidence?: readonly RevocationEvidenceInput[];
70
+ /** Evaluation time. Defaults to `new Date()`. */
71
+ readonly at?: Date;
72
+ /** Clock-skew tolerance in milliseconds. */
73
+ readonly clockSkewMs?: number;
74
+ }
75
+ /** Error codes that {@linkcode checkCertificateRevocation} may surface inside an `unknown` result. */
76
+ type CheckCertificateRevocationErrorCode = "revocation_evidence_missing" | "revocation_status_unknown";
77
+ /** Why a particular piece of evidence could not produce a definitive `good`/`revoked` answer. */
78
+ type RevocationIndeterminateReasonCode = "certificate_status_missing" | "certificate_status_unknown" | "crl_sign_not_permitted" | "issuer_mismatch" | "non_applicable" | "nonce_mismatch" | "ocsp_signing_missing" | "request_mismatch" | "responder_id_mismatch" | "responder_chain_invalid" | "response_status_invalid" | "signature_invalid" | "stale_crl" | "stale_response";
79
+ /** One piece of evidence that failed to produce a definitive revocation answer. */
80
+ interface RevocationIndeterminateEvidence {
81
+ /** Whether this evidence was CRL or OCSP. */
82
+ readonly source: RevocationEvidenceKind;
83
+ /** Machine-readable reason code. */
84
+ readonly code: RevocationIndeterminateReasonCode;
85
+ /** Human-readable explanation. */
86
+ readonly message: string;
87
+ /** CRL-specific applicability failure reason, when `source` is `'crl'`. */
88
+ readonly reason?: CrlApplicabilityFailureReason;
89
+ }
90
+ /** Diagnostic details attached to an `unknown` revocation result. */
91
+ interface CheckCertificateRevocationFailureDetails {
92
+ /** Which evidence kinds were attempted (`'crl'`, `'ocsp'`, or both). */
93
+ readonly checkedSources: readonly RevocationEvidenceKind[];
94
+ /** Per-evidence explanations of why no definitive answer was reached. */
95
+ readonly indeterminateEvidence: readonly RevocationIndeterminateEvidence[];
96
+ }
97
+ /** Revocation status could not be determined from the provided evidence. */
98
+ interface RevocationCheckUnknownValue {
99
+ /** Status is indeterminate. */
100
+ readonly status: Extract<RevocationStatus, "unknown">;
101
+ /** Why revocation status is unknown. */
102
+ readonly code: CheckCertificateRevocationErrorCode;
103
+ /** Human-readable diagnostic message. */
104
+ readonly message: string;
105
+ /** What evidence was attempted and why each failed. */
106
+ readonly details: CheckCertificateRevocationFailureDetails;
107
+ }
108
+ /** Certificate is not revoked according to the checked evidence. */
109
+ interface RevocationCheckGoodValue {
110
+ /** Certificate is not revoked. */
111
+ readonly status: Extract<RevocationStatus, "good">;
112
+ /** Which evidence kind confirmed the good status. */
113
+ readonly source: RevocationEvidenceKind;
114
+ /** Human-readable diagnostic message. */
115
+ readonly message: string;
116
+ }
117
+ /** Certificate is revoked according to the checked evidence. */
118
+ interface RevocationCheckRevokedValue {
119
+ /** Certificate is revoked. */
120
+ readonly status: Extract<RevocationStatus, "revoked">;
121
+ /** Which evidence kind reported the revocation. */
122
+ readonly source: RevocationEvidenceKind;
123
+ /** Human-readable diagnostic message. */
124
+ readonly message: string;
125
+ /** When the certificate was revoked (from CRL entry or OCSP response). */
126
+ readonly revokedAt?: Date;
127
+ /** CRL reason string (from CRL evidence). */
128
+ readonly revocationReason?: RevocationReason;
129
+ /** CRL reason integer code (from OCSP evidence). */
130
+ readonly revocationReasonCode?: number;
131
+ }
132
+ /** Discriminated union of `good`, `revoked`, and `unknown` revocation outcomes. */
133
+ type CheckCertificateRevocationValue = RevocationCheckGoodValue | RevocationCheckRevokedValue | RevocationCheckUnknownValue;
134
+ /**
135
+ * Result of {@linkcode checkCertificateRevocation}. Always succeeds (`ok: true`) —
136
+ * the `value.status` discriminator carries the actual outcome.
137
+ */
138
+ type CheckCertificateRevocationResult = Result<CheckCertificateRevocationValue, never>;
139
+ /** Extracts OCSP responder URIs from the certificate's Authority Information Access extension. */
140
+ declare function getCertificateOcspResponderUris(certificate: RevocationCertificateSource): readonly string[];
141
+ /**
142
+ * Merges configured OCSP responders with those discovered from the certificate's
143
+ * AIA extension. Configured responders take priority; duplicates are deduplicated by URI.
144
+ */
145
+ declare function resolveOcspResponderCandidates(input: ResolveOcspResponderCandidatesInput): readonly OcspResponderCandidate[];
146
+ /**
147
+ * Evaluates all provided CRL and OCSP evidence to determine the certificate's
148
+ * revocation status. Returns the first `revoked` if any, else the first `good`,
149
+ * else `unknown` with diagnostic details about each indeterminate evidence.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * import { checkCertificateRevocation } from 'micro509';
154
+ *
155
+ * const result = await checkCertificateRevocation({
156
+ * certificate: leafPem,
157
+ * issuerCertificate: caPem,
158
+ * evidence: [{ kind: 'crl', crl: crlPem }],
159
+ * });
160
+ * if (result.ok && result.value.status === 'revoked') {
161
+ * console.log('revoked at', result.value.revokedAt);
162
+ * }
163
+ * ```
164
+ */
165
+ declare function checkCertificateRevocation(input: CheckCertificateRevocationInput): Promise<CheckCertificateRevocationResult>;
166
+ //#endregion
167
+ export { type CertificateRevocationListMaterial, type CheckCertificateRevocationAgainstCrlErrorCode, type CheckCertificateRevocationAgainstCrlFailure, type CheckCertificateRevocationAgainstCrlFailureDetails, type CheckCertificateRevocationAgainstCrlGoodValue, type CheckCertificateRevocationAgainstCrlInput, type CheckCertificateRevocationAgainstCrlResult, type CheckCertificateRevocationAgainstCrlRevokedValue, type CheckCertificateRevocationAgainstCrlValue, CheckCertificateRevocationErrorCode, CheckCertificateRevocationFailureDetails, CheckCertificateRevocationInput, CheckCertificateRevocationResult, CheckCertificateRevocationValue, ConfiguredOcspResponder, ConfiguredOcspResponderCertificate, type CreateCertificateRevocationListInput, type CreateOcspRequestInput, type CreateOcspRequestItemInput, type CreateOcspResponseInput, type CreateOcspSingleResponseInput, type CrlApplicabilityFailureReason, type CrlCertificateSource, type CrlSource, type OcspCertStatus, type OcspCertificateSource, type OcspHashAlgorithm, type OcspRequestMaterial, type OcspRequestSource, OcspResponderCandidate, OcspResponderSource, type OcspResponseMaterial, type OcspResponseStatus, type ParsedCertificateRevocationList, type ParsedOcspCertId, type ParsedOcspRequest, type ParsedOcspResponderId, type ParsedOcspResponse, type ParsedOcspSingleResponse, type ParsedRevokedCertificate, ResolveOcspResponderCandidatesInput, RevocationCertificateSource, RevocationCheckGoodValue, RevocationCheckRevokedValue, RevocationCheckUnknownValue, RevocationCrlEvidenceInput, RevocationEvidenceInput, RevocationEvidenceKind, RevocationIndeterminateEvidence, RevocationIndeterminateReasonCode, RevocationOcspEvidenceInput, type RevocationReason, RevocationStatus, type RevokedCertificateInput, type ValidateCertificateRevocationListFailure, type ValidateCertificateRevocationListInput, type ValidateCertificateRevocationListResult, type ValidateOcspResponseFailure, type ValidateOcspResponseInput, type ValidateOcspResponseResult, type VerifyCertificateRevocationListFailure, type VerifyCertificateRevocationListResult, type VerifyOcspResponseFailure, type VerifyOcspResponseResult, checkCertificateRevocation, type checkCertificateRevocationAgainstCrl, type createCertificateRevocationList, type createOcspRequest, type createOcspResponse, getCertificateOcspResponderUris, type isCertificateRevoked, type parseCertificateRevocationListDer, type parseCertificateRevocationListPem, type parseOcspRequestDer, type parseOcspRequestPem, type parseOcspResponseDer, type parseOcspResponsePem, resolveOcspResponderCandidates, type validateCertificateRevocationList, type validateOcspResponse, type verifyCertificateRevocationList, type verifyOcspResponse };
168
+ //# sourceMappingURL=revocation.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{parseCertificateDer as e,parseCertificateFromSource as t}from"../x509/parse.js";import{checkCertificateRevocationAgainstCrl as n}from"./crl.js";import{validateOcspResponse as r}from"./ocsp.js";function i(e){let t;try{t=l(e)}catch{return[]}let n=[],r=new Set;for(let e of t.authorityInfoAccess??[])e.method!==`ocsp`||r.has(e.uri)||(r.add(e.uri),n.push(e.uri));return n}function a(e){let t=[],n=new Map;for(let t of e.configuredResponders??[]){let e=n.get(t.uri);(e===void 0||e.responderCertificate===void 0&&t.responderCertificate!==void 0)&&n.set(t.uri,t)}let r=new Set;for(let e of n.values())r.add(e.uri),t.push({source:`configured`,uri:e.uri,...e.responderCertificate===void 0?{}:{responderCertificate:e.responderCertificate}});for(let n of i(e.certificate))r.has(n)||(r.add(n),t.push({source:`authorityInfoAccess`,uri:n}));return t}async function o(e){let t=e.evidence??[],n=t.map(e=>e.kind);if(t.length===0)return f({status:`unknown`,code:`revocation_evidence_missing`,message:`No CRL or OCSP evidence provided`,details:{checkedSources:n,indeterminateEvidence:[]}});let r;try{r=l(e.certificate)}catch{return f({status:`unknown`,code:`revocation_status_unknown`,message:`Certificate input is malformed`,details:{checkedSources:n,indeterminateEvidence:[]}})}let i,a=[];for(let n of t){let t;try{t=n.kind===`crl`?await s(e,n,r):await c(e,n,r)}catch{a.push({source:n.kind,code:`signature_invalid`,message:`${n.kind.toUpperCase()} evidence input is malformed`});continue}if(t.status===`revoked`)return f(t.result);if(t.status===`good`){i??=t.result;continue}a.push(t.detail)}return f(i===void 0?{status:`unknown`,code:`revocation_status_unknown`,message:`No revocation evidence established certificate status`,details:{checkedSources:n,indeterminateEvidence:a}}:i)}async function s(e,t,r){let i=await n({certificate:r,issuerCertificate:e.issuerCertificate,crl:t.crl,...t.deltaCrl===void 0?{}:{deltaCrl:t.deltaCrl},...e.at===void 0?{}:{at:e.at},...e.clockSkewMs===void 0?{}:{clockSkewMs:e.clockSkewMs}});return i.ok?i.value.status===`revoked`?{status:`revoked`,result:{status:`revoked`,source:`crl`,message:`Certificate is revoked according to CRL evidence`,revokedAt:i.value.revocationDate,...i.value.reasonCode===void 0?{}:{revocationReason:i.value.reasonCode}}}:{status:`good`,result:{status:`good`,source:`crl`,message:`Certificate is not revoked according to CRL evidence`}}:{status:`unknown`,detail:{source:`crl`,code:i.code,message:i.message,...i.details?.reason===void 0?{}:{reason:i.details.reason}}}}async function c(e,t,n){let i=await r({response:t.response,issuerCertificate:e.issuerCertificate,...t.request===void 0?{}:{request:t.request},...t.responderCertificate===void 0?{}:{responderCertificate:t.responderCertificate},...e.at===void 0?{}:{at:e.at},...e.clockSkewMs===void 0?{}:{clockSkewMs:e.clockSkewMs}});if(!i.ok)return{status:`unknown`,detail:{source:`ocsp`,code:i.code,message:i.message}};let a=i.value.responses?.find(e=>d(e.certId.serialNumberHex)===d(n.serialNumberHex));return a===void 0?{status:`unknown`,detail:{source:`ocsp`,code:`certificate_status_missing`,message:`OCSP response does not include certificate status for the target certificate`}}:a.certStatus===`revoked`?{status:`revoked`,result:{status:`revoked`,source:`ocsp`,message:`Certificate is revoked according to OCSP evidence`,...a.revokedAt===void 0?{}:{revokedAt:a.revokedAt},...a.revocationReasonCode===void 0?{}:{revocationReasonCode:a.revocationReasonCode}}}:a.certStatus===`good`?{status:`good`,result:{status:`good`,source:`ocsp`,message:`Certificate is not revoked according to OCSP evidence`}}:{status:`unknown`,detail:{source:`ocsp`,code:`certificate_status_unknown`,message:`OCSP responder returned certificate status unknown`}}}function l(n){return u(n)?e(new Uint8Array(n.der)):t(n)}function u(e){return typeof e!=`string`&&`subjectPublicKeyInfoDer`in e}function d(e){return e.toLowerCase()}function f(e){return{ok:!0,value:e}}export{o as checkCertificateRevocation,i as getCertificateOcspResponderUris,a as resolveOcspResponderCandidates};
2
+ //# sourceMappingURL=revocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocation.js","names":[],"sources":["../../src/revocation/revocation.ts"],"sourcesContent":["/**\n * Revocation orchestration: evaluates CRL and OCSP evidence to produce a\n * unified `good`/`revoked`/`unknown` status for a certificate.\n *\n * @module\n */\n\nimport type { Result } from '#micro509/result/result.ts';\nimport type { ParsedCertificate } from '#micro509/x509/parse.ts';\nimport { parseCertificateDer, parseCertificateFromSource } from '#micro509/x509/parse.ts';\nimport type { CrlApplicabilityFailureReason, CrlSource, RevocationReason } from './crl.ts';\nimport { checkCertificateRevocationAgainstCrl } from './crl.ts';\nimport type { OcspCertificateSource, OcspRequestSource, ParsedOcspResponse } from './ocsp.ts';\nimport { validateOcspResponse } from './ocsp.ts';\n\nexport type * from './crl.ts';\nexport type * from './ocsp.ts';\n\n/** Unified revocation outcome across CRL and OCSP evidence. */\nexport type RevocationStatus = 'good' | 'revoked' | 'unknown';\n\n/** Which revocation mechanism produced the evidence. */\nexport type RevocationEvidenceKind = 'crl' | 'ocsp';\n/** PEM string, DER bytes, or already-parsed certificate. */\nexport type RevocationCertificateSource = string | Uint8Array | ParsedCertificate;\n/** Where the OCSP responder URI came from. */\nexport type OcspResponderSource = 'configured' | 'authorityInfoAccess';\n/** PEM or DER bytes of a pre-configured OCSP responder certificate. */\nexport type ConfiguredOcspResponderCertificate = string | Uint8Array;\n\n/** A manually-configured OCSP responder endpoint. */\nexport interface ConfiguredOcspResponder {\n\t/** OCSP responder URI (typically `http://...`). */\n\treadonly uri: string;\n\t/** Known responder certificate — skips embedded-certificate discovery. */\n\treadonly responderCertificate?: ConfiguredOcspResponderCertificate;\n}\n\n/** One candidate OCSP responder resolved by {@linkcode resolveOcspResponderCandidates}. */\nexport interface OcspResponderCandidate {\n\t/** Whether this candidate came from configuration or the certificate's AIA extension. */\n\treadonly source: OcspResponderSource;\n\t/** OCSP responder URI. */\n\treadonly uri: string;\n\t/** Pre-known responder certificate, if available. */\n\treadonly responderCertificate?: ConfiguredOcspResponderCertificate;\n}\n\n/** Input for {@linkcode resolveOcspResponderCandidates}. */\nexport interface ResolveOcspResponderCandidatesInput {\n\t/** Certificate whose AIA extension will be inspected for OCSP URIs. */\n\treadonly certificate: RevocationCertificateSource;\n\t/** Manually-configured responders — checked before AIA-derived ones. */\n\treadonly configuredResponders?: readonly ConfiguredOcspResponder[];\n}\n\n/** CRL-based revocation evidence for {@linkcode CheckCertificateRevocationInput.evidence}. */\nexport interface RevocationCrlEvidenceInput {\n\t/** Discriminator for the CRL evidence variant. */\n\treadonly kind: 'crl';\n\t/** Complete (base) CRL. */\n\treadonly crl: CrlSource;\n\t/** Optional delta CRL for more recent revocation information. */\n\treadonly deltaCrl?: CrlSource;\n}\n\n/** OCSP-based revocation evidence for {@linkcode CheckCertificateRevocationInput.evidence}. */\nexport interface RevocationOcspEvidenceInput {\n\t/** Discriminator for the OCSP evidence variant. */\n\treadonly kind: 'ocsp';\n\t/** OCSP response to validate. */\n\treadonly response: string | Uint8Array | ParsedOcspResponse;\n\t/** Original OCSP request — enables nonce and coverage checks. */\n\treadonly request?: OcspRequestSource;\n\t/** Explicit responder certificate — overrides embedded certificate discovery. */\n\treadonly responderCertificate?: OcspCertificateSource;\n}\n\n/** Discriminated union of CRL and OCSP evidence inputs. */\nexport type RevocationEvidenceInput = RevocationCrlEvidenceInput | RevocationOcspEvidenceInput;\n\n/** Input for {@linkcode checkCertificateRevocation}. */\nexport interface CheckCertificateRevocationInput {\n\t/** Certificate whose revocation status to determine. */\n\treadonly certificate: RevocationCertificateSource;\n\t/** Issuer of `certificate`. */\n\treadonly issuerCertificate: RevocationCertificateSource;\n\t/** CRL and/or OCSP evidence to evaluate. Returns `unknown` if empty. */\n\treadonly evidence?: readonly RevocationEvidenceInput[];\n\t/** Evaluation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** Clock-skew tolerance in milliseconds. */\n\treadonly clockSkewMs?: number;\n}\n\n/** Error codes that {@linkcode checkCertificateRevocation} may surface inside an `unknown` result. */\nexport type CheckCertificateRevocationErrorCode =\n\t| 'revocation_evidence_missing'\n\t| 'revocation_status_unknown';\n\n/** Why a particular piece of evidence could not produce a definitive `good`/`revoked` answer. */\nexport type RevocationIndeterminateReasonCode =\n\t| 'certificate_status_missing'\n\t| 'certificate_status_unknown'\n\t| 'crl_sign_not_permitted'\n\t| 'issuer_mismatch'\n\t| 'non_applicable'\n\t| 'nonce_mismatch'\n\t| 'ocsp_signing_missing'\n\t| 'request_mismatch'\n\t| 'responder_id_mismatch'\n\t| 'responder_chain_invalid'\n\t| 'response_status_invalid'\n\t| 'signature_invalid'\n\t| 'stale_crl'\n\t| 'stale_response';\n\n/** One piece of evidence that failed to produce a definitive revocation answer. */\nexport interface RevocationIndeterminateEvidence {\n\t/** Whether this evidence was CRL or OCSP. */\n\treadonly source: RevocationEvidenceKind;\n\t/** Machine-readable reason code. */\n\treadonly code: RevocationIndeterminateReasonCode;\n\t/** Human-readable explanation. */\n\treadonly message: string;\n\t/** CRL-specific applicability failure reason, when `source` is `'crl'`. */\n\treadonly reason?: CrlApplicabilityFailureReason;\n}\n\n/** Diagnostic details attached to an `unknown` revocation result. */\nexport interface CheckCertificateRevocationFailureDetails {\n\t/** Which evidence kinds were attempted (`'crl'`, `'ocsp'`, or both). */\n\treadonly checkedSources: readonly RevocationEvidenceKind[];\n\t/** Per-evidence explanations of why no definitive answer was reached. */\n\treadonly indeterminateEvidence: readonly RevocationIndeterminateEvidence[];\n}\n\n/** Revocation status could not be determined from the provided evidence. */\nexport interface RevocationCheckUnknownValue {\n\t/** Status is indeterminate. */\n\treadonly status: Extract<RevocationStatus, 'unknown'>;\n\t/** Why revocation status is unknown. */\n\treadonly code: CheckCertificateRevocationErrorCode;\n\t/** Human-readable diagnostic message. */\n\treadonly message: string;\n\t/** What evidence was attempted and why each failed. */\n\treadonly details: CheckCertificateRevocationFailureDetails;\n}\n\n/** Certificate is not revoked according to the checked evidence. */\nexport interface RevocationCheckGoodValue {\n\t/** Certificate is not revoked. */\n\treadonly status: Extract<RevocationStatus, 'good'>;\n\t/** Which evidence kind confirmed the good status. */\n\treadonly source: RevocationEvidenceKind;\n\t/** Human-readable diagnostic message. */\n\treadonly message: string;\n}\n\n/** Certificate is revoked according to the checked evidence. */\nexport interface RevocationCheckRevokedValue {\n\t/** Certificate is revoked. */\n\treadonly status: Extract<RevocationStatus, 'revoked'>;\n\t/** Which evidence kind reported the revocation. */\n\treadonly source: RevocationEvidenceKind;\n\t/** Human-readable diagnostic message. */\n\treadonly message: string;\n\t/** When the certificate was revoked (from CRL entry or OCSP response). */\n\treadonly revokedAt?: Date;\n\t/** CRL reason string (from CRL evidence). */\n\treadonly revocationReason?: RevocationReason;\n\t/** CRL reason integer code (from OCSP evidence). */\n\treadonly revocationReasonCode?: number;\n}\n\n/** Discriminated union of `good`, `revoked`, and `unknown` revocation outcomes. */\nexport type CheckCertificateRevocationValue =\n\t| RevocationCheckGoodValue\n\t| RevocationCheckRevokedValue\n\t| RevocationCheckUnknownValue;\n\n/**\n * Result of {@linkcode checkCertificateRevocation}. Always succeeds (`ok: true`) —\n * the `value.status` discriminator carries the actual outcome.\n */\nexport type CheckCertificateRevocationResult = Result<CheckCertificateRevocationValue, never>;\n\n/** Internal intermediate result from evaluating a single piece of revocation evidence. */\ntype RevocationEvidenceCheck =\n\t| { readonly status: 'good'; readonly result: RevocationCheckGoodValue }\n\t| { readonly status: 'revoked'; readonly result: RevocationCheckRevokedValue }\n\t| { readonly status: 'unknown'; readonly detail: RevocationIndeterminateEvidence };\n\n/** Extracts OCSP responder URIs from the certificate's Authority Information Access extension. */\nexport function getCertificateOcspResponderUris(\n\tcertificate: RevocationCertificateSource,\n): readonly string[] {\n\tlet parsedCertificate: ParsedCertificate;\n\ttry {\n\t\tparsedCertificate = normalizeCertificate(certificate);\n\t} catch {\n\t\treturn [];\n\t}\n\tconst uris: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const accessDescription of parsedCertificate.authorityInfoAccess ?? []) {\n\t\tif (accessDescription.method !== 'ocsp' || seen.has(accessDescription.uri)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(accessDescription.uri);\n\t\turis.push(accessDescription.uri);\n\t}\n\treturn uris;\n}\n\n/**\n * Merges configured OCSP responders with those discovered from the certificate's\n * AIA extension. Configured responders take priority; duplicates are deduplicated by URI.\n */\nexport function resolveOcspResponderCandidates(\n\tinput: ResolveOcspResponderCandidatesInput,\n): readonly OcspResponderCandidate[] {\n\tconst candidates: OcspResponderCandidate[] = [];\n\tconst configuredByUri = new Map<string, ConfiguredOcspResponder>();\n\tfor (const configuredResponder of input.configuredResponders ?? []) {\n\t\tconst existing = configuredByUri.get(configuredResponder.uri);\n\t\tif (\n\t\t\texisting === undefined ||\n\t\t\t(existing.responderCertificate === undefined &&\n\t\t\t\tconfiguredResponder.responderCertificate !== undefined)\n\t\t) {\n\t\t\tconfiguredByUri.set(configuredResponder.uri, configuredResponder);\n\t\t}\n\t}\n\tconst seen = new Set<string>();\n\tfor (const configuredResponder of configuredByUri.values()) {\n\t\tseen.add(configuredResponder.uri);\n\t\tcandidates.push({\n\t\t\tsource: 'configured',\n\t\t\turi: configuredResponder.uri,\n\t\t\t...(configuredResponder.responderCertificate === undefined\n\t\t\t\t? {}\n\t\t\t\t: { responderCertificate: configuredResponder.responderCertificate }),\n\t\t});\n\t}\n\tfor (const uri of getCertificateOcspResponderUris(input.certificate)) {\n\t\tif (seen.has(uri)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(uri);\n\t\tcandidates.push({\n\t\t\tsource: 'authorityInfoAccess',\n\t\t\turi,\n\t\t});\n\t}\n\treturn candidates;\n}\n\n/**\n * Evaluates all provided CRL and OCSP evidence to determine the certificate's\n * revocation status. Returns the first `revoked` if any, else the first `good`,\n * else `unknown` with diagnostic details about each indeterminate evidence.\n *\n * @example\n * ```ts\n * import { checkCertificateRevocation } from 'micro509';\n *\n * const result = await checkCertificateRevocation({\n * certificate: leafPem,\n * issuerCertificate: caPem,\n * evidence: [{ kind: 'crl', crl: crlPem }],\n * });\n * if (result.ok && result.value.status === 'revoked') {\n * console.log('revoked at', result.value.revokedAt);\n * }\n * ```\n */\nexport async function checkCertificateRevocation(\n\tinput: CheckCertificateRevocationInput,\n): Promise<CheckCertificateRevocationResult> {\n\tconst evidence = input.evidence ?? [];\n\tconst checkedSources = evidence.map((entry) => entry.kind);\n\tif (evidence.length === 0) {\n\t\treturn revocationSuccess({\n\t\t\tstatus: 'unknown',\n\t\t\tcode: 'revocation_evidence_missing',\n\t\t\tmessage: 'No CRL or OCSP evidence provided',\n\t\t\tdetails: {\n\t\t\t\tcheckedSources,\n\t\t\t\tindeterminateEvidence: [],\n\t\t\t},\n\t\t});\n\t}\n\tlet normalizedCertificate: ParsedCertificate;\n\ttry {\n\t\tnormalizedCertificate = normalizeCertificate(input.certificate);\n\t} catch {\n\t\treturn revocationSuccess({\n\t\t\tstatus: 'unknown',\n\t\t\tcode: 'revocation_status_unknown',\n\t\t\tmessage: 'Certificate input is malformed',\n\t\t\tdetails: {\n\t\t\t\tcheckedSources,\n\t\t\t\tindeterminateEvidence: [],\n\t\t\t},\n\t\t});\n\t}\n\tlet goodResult: RevocationCheckGoodValue | undefined;\n\tconst indeterminateEvidence: RevocationIndeterminateEvidence[] = [];\n\tfor (const entry of evidence) {\n\t\tlet result: RevocationEvidenceCheck;\n\t\ttry {\n\t\t\tresult =\n\t\t\t\tentry.kind === 'crl'\n\t\t\t\t\t? await checkCertificateRevocationWithCrl(input, entry, normalizedCertificate)\n\t\t\t\t\t: await checkCertificateRevocationWithOcsp(input, entry, normalizedCertificate);\n\t\t} catch {\n\t\t\tindeterminateEvidence.push({\n\t\t\t\tsource: entry.kind,\n\t\t\t\tcode: 'signature_invalid',\n\t\t\t\tmessage: `${entry.kind.toUpperCase()} evidence input is malformed`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (result.status === 'revoked') {\n\t\t\treturn revocationSuccess(result.result);\n\t\t}\n\t\tif (result.status === 'good') {\n\t\t\tgoodResult ??= result.result;\n\t\t\tcontinue;\n\t\t}\n\t\tindeterminateEvidence.push(result.detail);\n\t}\n\tif (goodResult !== undefined) {\n\t\treturn revocationSuccess(goodResult);\n\t}\n\treturn revocationSuccess({\n\t\tstatus: 'unknown',\n\t\tcode: 'revocation_status_unknown',\n\t\tmessage: 'No revocation evidence established certificate status',\n\t\tdetails: {\n\t\t\tcheckedSources,\n\t\t\tindeterminateEvidence,\n\t\t},\n\t});\n}\n\n/** Evaluates a single CRL evidence entry via {@linkcode checkCertificateRevocationAgainstCrl}. */\nasync function checkCertificateRevocationWithCrl(\n\tinput: CheckCertificateRevocationInput,\n\tevidence: RevocationCrlEvidenceInput,\n\tcertificate: ParsedCertificate,\n): Promise<RevocationEvidenceCheck> {\n\tconst result = await checkCertificateRevocationAgainstCrl({\n\t\tcertificate,\n\t\tissuerCertificate: input.issuerCertificate,\n\t\tcrl: evidence.crl,\n\t\t...(evidence.deltaCrl === undefined ? {} : { deltaCrl: evidence.deltaCrl }),\n\t\t...(input.at === undefined ? {} : { at: input.at }),\n\t\t...(input.clockSkewMs === undefined ? {} : { clockSkewMs: input.clockSkewMs }),\n\t});\n\tif (result.ok) {\n\t\tif (result.value.status === 'revoked') {\n\t\t\treturn {\n\t\t\t\tstatus: 'revoked',\n\t\t\t\tresult: {\n\t\t\t\t\tstatus: 'revoked',\n\t\t\t\t\tsource: 'crl',\n\t\t\t\t\tmessage: 'Certificate is revoked according to CRL evidence',\n\t\t\t\t\trevokedAt: result.value.revocationDate,\n\t\t\t\t\t...(result.value.reasonCode === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { revocationReason: result.value.reasonCode }),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tstatus: 'good',\n\t\t\tresult: {\n\t\t\t\tstatus: 'good',\n\t\t\t\tsource: 'crl',\n\t\t\t\tmessage: 'Certificate is not revoked according to CRL evidence',\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 'unknown',\n\t\tdetail: {\n\t\t\tsource: 'crl',\n\t\t\tcode: result.code,\n\t\t\tmessage: result.message,\n\t\t\t...(result.details?.reason === undefined ? {} : { reason: result.details.reason }),\n\t\t},\n\t};\n}\n\n/** Evaluates a single OCSP evidence entry via {@linkcode validateOcspResponse}. */\nasync function checkCertificateRevocationWithOcsp(\n\tinput: CheckCertificateRevocationInput,\n\tevidence: RevocationOcspEvidenceInput,\n\tcertificate: ParsedCertificate,\n): Promise<RevocationEvidenceCheck> {\n\tconst response = await validateOcspResponse({\n\t\tresponse: evidence.response,\n\t\tissuerCertificate: input.issuerCertificate,\n\t\t...(evidence.request === undefined ? {} : { request: evidence.request }),\n\t\t...(evidence.responderCertificate === undefined\n\t\t\t? {}\n\t\t\t: { responderCertificate: evidence.responderCertificate }),\n\t\t...(input.at === undefined ? {} : { at: input.at }),\n\t\t...(input.clockSkewMs === undefined ? {} : { clockSkewMs: input.clockSkewMs }),\n\t});\n\tif (!response.ok) {\n\t\treturn {\n\t\t\tstatus: 'unknown',\n\t\t\tdetail: {\n\t\t\t\tsource: 'ocsp',\n\t\t\t\tcode: response.code,\n\t\t\t\tmessage: response.message,\n\t\t\t},\n\t\t};\n\t}\n\tconst matchedResponse = response.value.responses?.find(\n\t\t(entry) =>\n\t\t\tnormalizeHex(entry.certId.serialNumberHex) === normalizeHex(certificate.serialNumberHex),\n\t);\n\tif (matchedResponse === undefined) {\n\t\treturn {\n\t\t\tstatus: 'unknown',\n\t\t\tdetail: {\n\t\t\t\tsource: 'ocsp',\n\t\t\t\tcode: 'certificate_status_missing',\n\t\t\t\tmessage: 'OCSP response does not include certificate status for the target certificate',\n\t\t\t},\n\t\t};\n\t}\n\tif (matchedResponse.certStatus === 'revoked') {\n\t\treturn {\n\t\t\tstatus: 'revoked',\n\t\t\tresult: {\n\t\t\t\tstatus: 'revoked',\n\t\t\t\tsource: 'ocsp',\n\t\t\t\tmessage: 'Certificate is revoked according to OCSP evidence',\n\t\t\t\t...(matchedResponse.revokedAt === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { revokedAt: matchedResponse.revokedAt }),\n\t\t\t\t...(matchedResponse.revocationReasonCode === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { revocationReasonCode: matchedResponse.revocationReasonCode }),\n\t\t\t},\n\t\t};\n\t}\n\tif (matchedResponse.certStatus === 'good') {\n\t\treturn {\n\t\t\tstatus: 'good',\n\t\t\tresult: {\n\t\t\t\tstatus: 'good',\n\t\t\t\tsource: 'ocsp',\n\t\t\t\tmessage: 'Certificate is not revoked according to OCSP evidence',\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 'unknown',\n\t\tdetail: {\n\t\t\tsource: 'ocsp',\n\t\t\tcode: 'certificate_status_unknown',\n\t\t\tmessage: 'OCSP responder returned certificate status unknown',\n\t\t},\n\t};\n}\n\n/** Accepts PEM, DER, or already-parsed certificate and returns a parsed certificate. */\nfunction normalizeCertificate(certificate: RevocationCertificateSource): ParsedCertificate {\n\treturn hasParsedCertificateShape(certificate)\n\t\t? parseCertificateDer(new Uint8Array(certificate.der))\n\t\t: parseCertificateFromSource(certificate);\n}\n\nfunction hasParsedCertificateShape(value: RevocationCertificateSource): value is ParsedCertificate {\n\treturn typeof value !== 'string' && 'subjectPublicKeyInfoDer' in value;\n}\n\n/** Lowercases a hex string for bytewise serial-number comparison. */\nfunction normalizeHex(value: string): string {\n\treturn value.toLowerCase();\n}\n\n/** Wraps a value into a successful `CheckCertificateRevocationResult`. */\nfunction revocationSuccess(\n\tvalue: CheckCertificateRevocationValue,\n): CheckCertificateRevocationResult {\n\treturn { ok: true, value };\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { CertificateRevocationListMaterial, CheckCertificateRevocationAgainstCrlErrorCode, CheckCertificateRevocationAgainstCrlFailure, CheckCertificateRevocationAgainstCrlFailureDetails, CheckCertificateRevocationAgainstCrlGoodValue, CheckCertificateRevocationAgainstCrlInput, CheckCertificateRevocationAgainstCrlResult, CheckCertificateRevocationAgainstCrlRevokedValue, CheckCertificateRevocationAgainstCrlValue, CreateCertificateRevocationListInput, CrlApplicabilityFailureReason, CrlCertificateSource, CrlSource, ParsedCertificateRevocationList, ParsedRevokedCertificate, RevocationReason, RevokedCertificateInput, ValidateCertificateRevocationListFailure, ValidateCertificateRevocationListInput, ValidateCertificateRevocationListResult, VerifyCertificateRevocationListFailure, VerifyCertificateRevocationListResult, checkCertificateRevocationAgainstCrl, createCertificateRevocationList, isCertificateRevoked, parseCertificateRevocationListDer, parseCertificateRevocationListPem, validateCertificateRevocationList, verifyCertificateRevocationList } from "./revocation/crl.js";
2
+ import { CreateOcspRequestInput, CreateOcspRequestItemInput, CreateOcspResponseInput, CreateOcspSingleResponseInput, OcspCertStatus, OcspCertificateSource, OcspHashAlgorithm, OcspRequestMaterial, OcspRequestSource, OcspResponseMaterial, OcspResponseStatus, ParsedOcspCertId, ParsedOcspRequest, ParsedOcspResponderId, ParsedOcspResponse, ParsedOcspSingleResponse, ValidateOcspResponseFailure, ValidateOcspResponseInput, ValidateOcspResponseResult, VerifyOcspResponseFailure, VerifyOcspResponseResult, createOcspRequest, createOcspResponse, parseOcspRequestDer, parseOcspRequestPem, parseOcspResponseDer, parseOcspResponsePem, validateOcspResponse, verifyOcspResponse } from "./revocation/ocsp.js";
3
+ import { CheckCertificateRevocationErrorCode, CheckCertificateRevocationFailureDetails, CheckCertificateRevocationInput, CheckCertificateRevocationResult, CheckCertificateRevocationValue, ConfiguredOcspResponder, ConfiguredOcspResponderCertificate, OcspResponderCandidate, OcspResponderSource, ResolveOcspResponderCandidatesInput, RevocationCertificateSource, RevocationCheckGoodValue, RevocationCheckRevokedValue, RevocationCheckUnknownValue, RevocationCrlEvidenceInput, RevocationEvidenceInput, RevocationEvidenceKind, RevocationIndeterminateEvidence, RevocationIndeterminateReasonCode, RevocationOcspEvidenceInput, RevocationStatus, checkCertificateRevocation, getCertificateOcspResponderUris, resolveOcspResponderCandidates } from "./revocation/revocation.js";
4
+ import { CertificateRevocationStatus, CertificateSource, CheckChainRevocationInput, CheckChainRevocationResult, CheckChainRevocationValue, OcspResponseSource, RevocationExecutionError, RevocationIndeterminateReason, RevocationPolicy, RevocationSource, checkChainRevocation } from "./revocation/chain.js";
5
+ export { type CertificateRevocationListMaterial, type CertificateRevocationStatus, type CertificateSource, type CheckCertificateRevocationAgainstCrlErrorCode, type CheckCertificateRevocationAgainstCrlFailure, type CheckCertificateRevocationAgainstCrlFailureDetails, type CheckCertificateRevocationAgainstCrlGoodValue, type CheckCertificateRevocationAgainstCrlInput, type CheckCertificateRevocationAgainstCrlResult, type CheckCertificateRevocationAgainstCrlRevokedValue, type CheckCertificateRevocationAgainstCrlValue, type CheckCertificateRevocationErrorCode, type CheckCertificateRevocationFailureDetails, type CheckCertificateRevocationInput, type CheckCertificateRevocationResult, type CheckCertificateRevocationValue, type CheckChainRevocationInput, type CheckChainRevocationResult, type CheckChainRevocationValue, type ConfiguredOcspResponder, type ConfiguredOcspResponderCertificate, type CreateCertificateRevocationListInput, type CreateOcspRequestInput, type CreateOcspRequestItemInput, type CreateOcspResponseInput, type CreateOcspSingleResponseInput, type CrlApplicabilityFailureReason, type CrlCertificateSource, type CrlSource, type OcspCertStatus, type OcspCertificateSource, type OcspHashAlgorithm, type OcspRequestMaterial, type OcspRequestSource, type OcspResponderCandidate, type OcspResponderSource, type OcspResponseMaterial, type OcspResponseSource, type OcspResponseStatus, type ParsedCertificateRevocationList, type ParsedOcspCertId, type ParsedOcspRequest, type ParsedOcspResponderId, type ParsedOcspResponse, type ParsedOcspSingleResponse, type ParsedRevokedCertificate, type ResolveOcspResponderCandidatesInput, type RevocationCertificateSource, type RevocationCheckGoodValue, type RevocationCheckRevokedValue, type RevocationCheckUnknownValue, type RevocationCrlEvidenceInput, type RevocationEvidenceInput, type RevocationEvidenceKind, type RevocationExecutionError, type RevocationIndeterminateEvidence, type RevocationIndeterminateReason, type RevocationIndeterminateReasonCode, type RevocationOcspEvidenceInput, type RevocationPolicy, type RevocationReason, type RevocationSource, type RevocationStatus, type RevokedCertificateInput, type ValidateCertificateRevocationListFailure, type ValidateCertificateRevocationListInput, type ValidateCertificateRevocationListResult, type ValidateOcspResponseFailure, type ValidateOcspResponseInput, type ValidateOcspResponseResult, type VerifyCertificateRevocationListFailure, type VerifyCertificateRevocationListResult, type VerifyOcspResponseFailure, type VerifyOcspResponseResult, checkCertificateRevocation, checkCertificateRevocationAgainstCrl, checkChainRevocation, createCertificateRevocationList, createOcspRequest, createOcspResponse, getCertificateOcspResponderUris, isCertificateRevoked, parseCertificateRevocationListDer, parseCertificateRevocationListPem, parseOcspRequestDer, parseOcspRequestPem, parseOcspResponseDer, parseOcspResponsePem, resolveOcspResponderCandidates, validateCertificateRevocationList, validateOcspResponse, verifyCertificateRevocationList, verifyOcspResponse };
@@ -0,0 +1 @@
1
+ import{checkCertificateRevocationAgainstCrl as e,createCertificateRevocationList as t,isCertificateRevoked as n,parseCertificateRevocationListDer as r,parseCertificateRevocationListPem as i,validateCertificateRevocationList as a,verifyCertificateRevocationList as o}from"./revocation/crl.js";import{checkChainRevocation as s}from"./revocation/chain.js";import{createOcspRequest as c,createOcspResponse as l,parseOcspRequestDer as u,parseOcspRequestPem as d,parseOcspResponseDer as f,parseOcspResponsePem as p,validateOcspResponse as m,verifyOcspResponse as h}from"./revocation/ocsp.js";import{checkCertificateRevocation as g,getCertificateOcspResponderUris as _,resolveOcspResponderCandidates as v}from"./revocation/revocation.js";export{g as checkCertificateRevocation,e as checkCertificateRevocationAgainstCrl,s as checkChainRevocation,t as createCertificateRevocationList,c as createOcspRequest,l as createOcspResponse,_ as getCertificateOcspResponderUris,n as isCertificateRevoked,r as parseCertificateRevocationListDer,i as parseCertificateRevocationListPem,u as parseOcspRequestDer,d as parseOcspRequestPem,f as parseOcspResponseDer,p as parseOcspResponsePem,v as resolveOcspResponderCandidates,a as validateCertificateRevocationList,m as validateOcspResponse,o as verifyCertificateRevocationList,h as verifyOcspResponse};