Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from node-forge to PKI.js #13894

Merged
merged 4 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/13894.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

ui: Add support for ECDSA and Ed25519 certificate views
```
43 changes: 36 additions & 7 deletions ui/app/helpers/parse-pki-cert.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,53 @@
import { helper } from '@ember/component/helper';
import { pki } from 'node-forge';
import * as asn1js from 'asn1js';
import { fromBase64, stringToArrayBuffer } from 'pvutils';
import { Certificate } from 'pkijs';

export function parsePkiCert([model]) {
// model has to be the responseJSON from PKI serializer
if (!model.certificate) {
return;
}
let cert;
// node-forge cannot parse EC (elliptical curve) certs
// set canParse to false if unable to convert a Forge cert from PEM
try {
cert = pki.certificateFromPem(model.certificate);
let cert_base64 = model.certificate.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, '');
let cert_der = fromBase64(cert_base64);
let cert_asn1 = asn1js.fromBER(stringToArrayBuffer(cert_der));
cert = new Certificate({ schema: cert_asn1.result });
} catch (error) {
console.log('Error parsing certificate:', error, model.certificate);
return {
can_parse: false,
};
}
const commonName = cert?.subject.getField('CN') ? cert.subject.getField('CN').value : null;
const expiryDate = cert?.validity.notAfter;
const issueDate = cert?.validity.notBefore;

// We wish to get the CN element out of this certificate's subject. A
// subject is a list of RDNs, where each RDN is a (type, value) tuple
// and where a type is an OID. The OID for CN can be found here:
//
// http://oid-info.com/get/2.5.4.3
// https://datatracker.ietf.org/doc/html/rfc5280#page-112
//
// Each value is then encoded as another ASN.1 object; in the case of a
// CommonName field, this is usually a PrintableString, BMPString, or a
// UTF8String. Regardless of encoding, it should be present in the
// valueBlock's value field if it is renderable.
const commonNameOID = '2.5.4.3';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linting hadn't run the first time, but it did now :-D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for breaking this down and making is so clear to follow. 😍

const commonNames = cert?.subject?.typesAndValues
.filter((rdn) => rdn?.type === commonNameOID)
.map((rdn) => rdn?.value?.valueBlock?.value);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case anyone was wondering, this does appear to be the correct way to parse the RDN's value: https://github.com/PeculiarVentures/PKI.js/blob/master/src/AttributeTypeAndValue.js#L213-L214


// Theoretically, there might be multiple (or no) CommonNames -- but Vault
// presently refuses to issue certificates without CommonNames in most
// cases. For now, return the first CommonName we find. Alternatively, we
// might update our callers to handle multiple, or join them using some
// separator like ','.
const commonName = commonNames ? (commonNames.length ? commonNames[0] : null) : null;

// Date instances are stored in the value field as the notAfter/notBefore
// field themselves are Time values.
const expiryDate = cert?.notAfter?.value;
const issueDate = cert?.notBefore?.value;
return {
can_parse: true,
common_name: commonName,
Expand Down
4 changes: 3 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@icholy/duration": "^5.1.0",
"@storybook/cli": "^6.3.10",
"@storybook/ember-cli-storybook": "^0.4.0",
"asn1js": "^2.2.0",
"autosize": "^4.0.0",
"babel-eslint": "^10.1.0",
"babel-plugin-inline-json-import": "^0.3.2",
Expand Down Expand Up @@ -156,13 +157,14 @@
"jsondiffpatch": "^0.4.1",
"jsonlint": "^1.6.3",
"loader.js": "^4.7.0",
"node-forge": "^0.10.0",
"node-sass": "^4.10.0",
"normalize.css": "4.1.1",
"npm-run-all": "^4.1.5",
"pkijs": "^2.2.2",
"pretender": "^3.4.3",
"prettier": "^2.2.1",
"prettier-eslint-cli": "^5.0.0",
"pvutils": "^1.0.17",
"qunit": "^2.14.1",
"qunit-dom": "^1.6.0",
"route-recognizer": "^0.3.4",
Expand Down
31 changes: 26 additions & 5 deletions ui/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5087,6 +5087,13 @@ asn1@~0.2.3:
dependencies:
safer-buffer "~2.1.0"

asn1js@^2.1.1, asn1js@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-2.2.0.tgz#d890fcdda86b8a005693df14a986bfb2c2069c57"
integrity sha512-oagLNqpfNv7CvmyMoexMDNyVDSiq1rya0AEUgcLlNHdHgNl6U/hi8xY370n5y+ZIFEXOx0J4B1qF2NDjMRxklA==
dependencies:
pvutils latest

assert-never@^1.1.0, assert-never@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe"
Expand Down Expand Up @@ -7353,6 +7360,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==

bytestreamjs@^1.0.29:
version "1.0.29"
resolved "https://registry.yarnpkg.com/bytestreamjs/-/bytestreamjs-1.0.29.tgz#691f8ee8e5a150c61b925993a3eec0911ed17f1d"
integrity sha512-Mri3yqoo9YvdaSvD5OYl4Rdu9zCBJInW/Ez31sdlNY4ikMy//EvTTmidfLcs0e+NBvKVEpPzYvJAesjgMdjnZg==

cacache@^12.0.2:
version "12.0.4"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c"
Expand Down Expand Up @@ -16125,11 +16137,6 @@ node-fetch@^2.6.1:
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==

node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==

node-gyp@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
Expand Down Expand Up @@ -17142,6 +17149,15 @@ pkg-up@^2.0.0:
dependencies:
find-up "^2.1.0"

pkijs@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/pkijs/-/pkijs-2.2.2.tgz#d0780379a2fb80c892c3ead4bcfb42675b67a982"
integrity sha512-xRTEW9LgUeHBe5hRCC4EHvLbO6o3L/t8uEk8cTaSMVEjEcy2G5qJ/bY2ndvrGgZlKDThnTrM4Xlwu8Qpyr6mOg==
dependencies:
asn1js "^2.1.1"
bytestreamjs "^1.0.29"
pvutils "^1.0.17"

please-upgrade-node@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
Expand Down Expand Up @@ -17615,6 +17631,11 @@ puppeteer-core@^2.1.1:
rimraf "^2.6.1"
ws "^6.1.0"

pvutils@^1.0.17, pvutils@latest:
version "1.0.17"
resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.0.17.tgz#ade3c74dfe7178944fe44806626bd2e249d996bf"
integrity sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==

q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
Expand Down