PeculiarVentures / PKI.js

PKI.js is a pure JavaScript library implementing the formats that are used in PKI applications (signing, encryption, certificate requests, OCSP and TSP requests/responses). It is built on WebCrypto (Web Cryptography API) and requires no plug-ins.
http://pkijs.org
Other
1.25k stars 204 forks source link

TypeError: element.toSchema is not a function while creating OCSP Request #354

Closed maliksajidhussain closed 2 years ago

maliksajidhussain commented 2 years ago

I am creating an ocsp requesting using a base64 certificate. When I try to print this request I get this error "TypeError: element.toSchema is not a function".

I am using the following sample code. Any thing wrong in the request creation? ocsp.zip

microshine commented 2 years ago

Please try to use the latest version of PKIjs. It uses TS implementation and includes type definitions. It should help you to fix some errors during development.

Here is TS implementation of your example with the latest PKIjs version

Click to expand! ```ts import * as asn1js from "asn1js"; import * as pkijs from "pkijs"; import { webcrypto } from "crypto"; const crypto = webcrypto as unknown as Crypto; let certBase64 = `MIIExzCCA6+gAwIBAgITB2jonhxbjaHIEwziC9Z7kM4GZjANBgkqhkiG9w0BAQsFADBIMUYwRAYDVQQDDD1DaXR5IG9mIE9zbWlvIFZpdGFsIFJlY29yZHMgRGVwYXJ0bWVudCBVdGlsaXR5IGFuZCBSZWxhdGVkIENBMB4XDTIyMDUxMzExMTQ1OFoXDTI0MDUxMzExMTQ1OFowXDELMAkGA1UEBhMCUEsxEDAOBgNVBAoMB0NvZGVnaWMxFjAUBgNVBAMMDUFkbWluaXN0cmF0b3IxIzAhBgkqhkiG9w0BCQEWFG1zLWFkbWluQGNvZGVnaWMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5O12qyGmR+J4n3+LpAAIVsME1S3U+zn949sDEtQSOU4kec2+9/5AV6beSmsmKwwFk3aNosnx/PhORAjH7yyeJ3y886hFM77cb/7UTp1xUKerdKha0fJW8TL9pkcytT8FgZXuiJpMUqa2x9qxsG4b1WwtzlAM2wJ2wJZyf19QI5l58hxPtTydMAKRpZyRCTidukGSlKwVdd0mn541z0816lmMw/02yEnJoUYSHT9Vl5zBy5KZ5fNuUdziePTMfViXJ6KC4FmfGDN0ZVYZrL2FI5yN+GAcdjUujpk1GgRbSSEUi20ZU4SIG+SuBjtIPdaZnr7/QpzPL85lOlK3B7wJWwIDAQABo4IBlDCCAZAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUoMxztFrxSuYdXIquArMgNwHfuqgwHwYDVR0jBBgwFoAU8xbZTB1oevI2tZS7JJJWDoSSX60wDgYDVR0PAQH/BAQDAgSwMBMGA1UdJQQMMAoGCCsGAQUFBwMEMHEGA1UdIARqMGgwZgYIKwYBBAGB+H0wWjAqBggrBgEFBQcCARYeaHR0cDovL29zbWlvLmNoL2Jhc2ljX2Nwcy5odG1sMCwGCCsGAQUFBwIBFiBodHRwOi8vb3NtaW8uY2gvdXRpbGl0eV9jcHMuaHRtbDA4BgNVHR8EMTAvMC2gK6AphidodHRwczovL3N0YWdpbmcuY2Eub3NtaW8uY2gvdXRpbGl0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMCwGCCsGAQUFBzABhiBodHRwczovL3N0YWdpbmcuY2Eub3NtaW8uY2gvb2NzcDAzBggrBgEFBQcwAoYnaHR0cHM6Ly9zdGFnaW5nLmNhLm9zbWlvLmNoL3V0aWxpdHkuY2VyMA0GCSqGSIb3DQEBCwUAA4IBAQCNBmjTTroE9CEpQ7/n6kWQq1ZD1G9j8r40k+0POp1uX209LXhMaoDZgPObfIOYLFRyXSoZk4JJSBnHzMmB0aD4psIXZgavAWbSKPAYH6bBDYmsrdOi76Eu0Ad3BZJrDCWReCeiYUQC7cPxr52SNqZz3Ap5tA51gGQe4qrpjqI79K9Q8yRx33mN/x+nzFcFMRo8bbwERD3Ys32eEMDOyzS09VwHmJrf2FJmZwuXY0YxlJ18ANmqXg/VfvbJ87Bx8tWyPe/aIp6V5P7kqWNPDCVgOBbLVfePx9Q50up9cxdP40CgX+dDPvCbIu9kTFtdjuUvKFm+ueZm/xt6kFFol6iq`; let ocspRequest = `MGAwXqEipCAwHjEcMAkGA1UEBhMCUlUwDwYDVQQDHggAVABlAHMAdDAfMB0wGzAHBgUrDgMCGgQEfwECAwQEfwECAwIEfwECA6IXMBUwEwYJKwYBBQUHMAECBAYEBH8BAgM=`; function str2ab(signatureBase64: string): ArrayBuffer { return new Uint8Array(Buffer.from(signatureBase64, "base64")).buffer; } async function startReq() { const asn1 = asn1js.fromBER(str2ab(certBase64)); const certificate = new pkijs.Certificate({ schema: asn1.result }); const ocspReq = await createOCSPRequest(certificate) let ocspUrl = getOCSPUrl(certificate); console.log(ocspUrl); const response = await sendOCSPRequest(ocspReq, ocspUrl) console.log(response); } async function sendOCSPRequest(ocspReq: pkijs.OCSPRequest, ocspUrl: string) { console.log(ocspReq); return new Promise((resolve, reject) => { setTimeout(() => { fetch(ocspUrl, { method: 'POST', headers: { 'Content-Type': 'application/ocsp-request', 'Access-Control-Allow-Origin': '*', }, body: ocspReq.toSchema(true).toBER(), }).then(response => response.json()).then(data => { resolve(data); }).catch((error) => { reject(error); }); }, 3000) }); } const rdnmap = { "2.5.4.6": "C", "2.5.4.10": "O", "2.5.4.11": "OU", "2.5.4.3": "CN", "2.5.4.7": "L", "2.5.4.8": "ST", "2.5.4.12": "T", "2.5.4.42": "GN", "2.5.4.43": "I", "2.5.4.4": "SN", "1.2.840.113549.1.9.1": "E-mail" }; async function createOCSPRequest(certificate: pkijs.Certificate) { const serialNumberValue = certificate.serialNumber.valueBlock.valueHex; const issuerNameHash = await crypto.subtle.digest({ name: "sha-1" }, certificate.issuer.toSchema().toBER()); // console.log(issuerNameHash); let authorityKeyIdentifier; for (let extension of certificate.extensions || []) { if (extension.extnID === '2.5.29.35') { authorityKeyIdentifier = extension; } } if (!authorityKeyIdentifier) { throw new Error("authorityKeyIdentifier extension not found") } let authorityKeyIdentifierValue = authorityKeyIdentifier.parsedValue.keyIdentifier.valueBlock.valueHex; // console.log(authorityKeyIdentifierValue); //region Initial variables let ocspReqSimpl = new pkijs.OCSPRequest(); //endregion // region Put static variables // ocspReqSimpl.tbsRequest.requestorName = new GeneralName({ // type: 4, // value: new RelativeDistinguishedNames({ // typesAndValues: [ // new AttributeTypeAndValue({ // type: "2.5.4.6", // Country name // value: new PrintableString({ value: "RU" }) // }), // new AttributeTypeAndValue({ // type: "2.5.4.3", // Common name // value: new BmpString({ value: "Test" }) // }) // ] // }) // }); const fictionBuffer = new ArrayBuffer(4); const fictionView = new Uint8Array(fictionBuffer); fictionView[0] = 0x7F; fictionView[1] = 0x01; fictionView[2] = 0x02; fictionView[3] = 0x03; ocspReqSimpl.tbsRequest.requestList = [new pkijs.Request({ reqCert: new pkijs.CertID({ hashAlgorithm: new pkijs.AlgorithmIdentifier({ algorithmId: "1.3.14.3.2.26" }), issuerNameHash: new asn1js.OctetString({ valueHex: issuerNameHash }), issuerKeyHash: new asn1js.OctetString({ valueHex: authorityKeyIdentifierValue }), serialNumber: new asn1js.Integer({ valueHex: serialNumberValue }) }) })]; const ocspNonceValue = generateNonce(); // console.log(ocspNonceValue); ocspReqSimpl.tbsRequest.requestExtensions = [ new pkijs.Extension({ extnID: "1.3.6.1.5.5.7.48.1.2", // ocspNonce extnValue: (new asn1js.OctetString({ valueHex: fictionBuffer })).toBER(false) }) ]; //endregion //region Encode OCSP request and put on the Web page let ocspReqBuffer = ocspReqSimpl.toSchema(true).toBER(false); console.log('ocspRequestData', Buffer.from(new Uint8Array(ocspReqBuffer)).toString('base64')) //endregion return Promise.resolve(ocspReqSimpl); } function getOCSPUrl(certificate: pkijs.Certificate) { let ocspUrl; let authorityInformationExtension; for (let extension of certificate.extensions || []) { // console.log(extension); if (extension.extnID === '1.3.6.1.5.5.7.1.1') { console.log("AIA extension found"); authorityInformationExtension = extension; } } let parsedOcspValue; if (authorityInformationExtension != undefined && authorityInformationExtension.parsedValue != undefined) { for (let parsedValue of authorityInformationExtension.parsedValue.accessDescriptions) { if (parsedValue.accessMethod === '1.3.6.1.5.5.7.48.1') { parsedOcspValue = parsedValue; } } } if (parsedOcspValue != undefined) { ocspUrl = parsedOcspValue.accessLocation.value; } return ocspUrl; } function generateNonce() { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 10; i++) text += possible.charCodeAt(Math.floor(Math.random() * possible.length)).toString(16); return text; } startReq(); ```

As you can see, it prints the OCSP request

OCSPRequest {
  tbsRequest: TBSRequest {
    tbsView: Uint8Array(0) [],
    requestList: [ [Request] ],
    requestExtensions: [ [Extension] ]
  }
}

View ASN.1 schema

maliksajidhussain commented 2 years ago

Thanks for the quick response. I am using simple JavaScript and created bundle js file and make some customization to export function and class of PKI js. Is there any bug in the older version of PKI JS?

rmhrisk commented 2 years ago

There are many bugs in older PKIjs.

YuryStrozhevsky commented 2 years ago

There are many bugs in older PKIjs.

@rmhrisk Could you, please, point me any of the "many bugs in older PKIjs"? For the years since I made PKIjs (about 7-8 years) I can remember only two real bugs both related to moving from ES3 to ES6. Maybe your "TypeScript moving team" found others?

microshine commented 2 years ago

Now you can use PKIjs without bundle file

<script type="module">
  import * as asn1js from "https://unpkg.com/asn1js@^3?module";
  import * as pkijs from "https://unpkg.com/pkijs@^3?module";

  // your code here
</script>
maliksajidhussain commented 2 years ago

Thanks @microshine for the help. My use case was to build OCSP request using offline pki javascript file. We cannot refer any online JS file. I am able to create the request. The issue was some of the classes missing in pki bundle.js.