SignedCms ComputeSignature throw CryptographicException “The parameter is incorrect.” - digital-signature

I try sign pdf using http://www.debenu.com/kb/advanced-options-signing-pdf-files/
But it throw exception when call
// Sign the file data (generates an SHA-1 hash and
// signs that hash)
byte[] enc = SignData(fileData, cert); //throw exception
Here is my SignData function
private static byte[] SignData(byte[] inputData, X509Certificate2 cert)
{
// Create an SHA-1 hash of the file data
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] sha1Result = sha.ComputeHash(inputData);
CmsSigner cmsSigner = new CmsSigner(cert);
cmsSigner.IncludeOption = X509IncludeOption.WholeChain;
cmsSigner.DigestAlgorithm = new Oid("SHA1");
// Sign the hash using the certificate
// This could be changed to use a hardware device (eg. smartcard)
ContentInfo content = new ContentInfo(sha1Result);
SignedCms signedCms = new SignedCms(SubjectIdentifierType.IssuerAndSerialNumber, content, true);
signedCms.ComputeSignature(cmsSigner, false); //throw "The parameter is incorrect."
return signedCms.Encode();
}
It is Ok when get testSig
byte[] randomData = new byte[1];
randomData[0] = 123;
byte[] testSig = SignData(randomData, cert);
This error throw when I use cert from usb token. If I choose other cert has private key it not throw error
Edit
I export from usb token to cer and here is it
openssl x509 -in xxx.cer -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
54:03:36:e0:8b:24:50:fe:01:27:6b:3c:a0:69:2a:81
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XX, L=XX, O=XX, CN=XXXX
Validity
Not Before: Aug 17 04:23:59 2017 GMT
Not After : May 15 03:35:48 2020 GMT
Subject: UID=XXXX, CN=xxxxx, C=XX
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:a1:ec:28:55:a6:39:25:c1:f1:1f:15:60:6c:5c:
d1:2e:8f:1d:4d:d2:f2:66:9c:11:49:71:fd:20:ce:
19:cc:03:c0:0b:85:65:e9:e1:25:ae:39:3a:48:9a:
b6:11:a1:bf:bb:e5:b8:75:28:9d:c8:02:c3:2c:e8:
41:e7:ff:c1:bd:3a:10:dc:41:a8:54:b9:52:0e:14:
3e:36:47:d4:39:63:0d:2c:10:b2:61:94:d3:3c:a4:
f1:2e:9d:02:b7:90:3b:26:dc:cc:8a:d1:7e:ea:0b:
f3:dd:d7:34:23:b8:e4:a6:f0:c6:49:8c:b6:a1:29:
b9:b4:26:e8:56:b0:38:46:75
Exponent: 65537 (0x10001)
X509v3 extensions:
Authority Information Access:
OCSP - URI:http://XXX
X509v3 Subject Key Identifier:
00:D3:2F:BE:59:19:4B:28:8C:F1:B7:82:1D:33:E7:EA:E7:BA:21:C4
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
keyid:1E:B0:0F:48:97:DF:D0:C3:67:A7:46:84:3B:58:3B:88:0D:53:94:86
X509v3 CRL Distribution Points:
URI:http://XXX/XXX.crl
CRLissuer:<UNSUPPORTED>
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
E-mail Protection, 1.3.6.1.4.1.311.10.3.12
Signature Algorithm: sha1WithRSAEncryption
14:6d:06:dc:fc:81:de:a8:87:85:49:cf:69:54:aa:c8:55:6f:
02:5a:d6:4d:c2:e6:f1:cd:7c:be:0e:1d:4c:1c:b1:5d:6a:8b:
b5:c9:d0:43:cd:a5:a2:ee:81:ca:60:1b:2c:54:87:ea:c7:a1:
49:dc:7c:73:cd:56:bd:5b:2b:65:38:49:8f:c7:11:00:09:de:
1d:b4:46:80:af:e9:ec:0c:45:9c:4f:f2:8a:6d:b9:1a:00:d9:
79:16:b8:78:4e:24:6a:08:6c:42:bf:bc:56:70:42:13:2b:0e:
be:5d:c5:71:79:7e:65:f0:e9:5e:57:c8:12:a3:6f:7c:52:0f:
c2:f1:f5:40:ea:a5:1f:92:51:a1:3f:55:75:46:5e:24:d9:3d:
c9:71:88:70:d8:df:cb:58:fc:15:2f:d8:ea:5e:25:11:cb:27:
10:71:1e:00:e5:f5:75:f1:cf:5e:c6:d6:8d:da:f4:76:99:0e:
f0:2a:33:bd:f1:04:1e:4f:96:d7:53:d4:1d:f2:9a:5f:1f:d8:
8e:81:4e:16:27:77:13:9f:50:53:82:f3:03:09:54:d6:d5:d2:
8b:d3:fa:56:38:a3:b5:43:e4:34:2d:be:e8:9b:37:98:29:de:
e5:d5:e7:5d:8d:de:d7:98:e2:96:cc:51:32:c2:dd:5b:4b:e8:
3e:10:86:3f
Exception at
at System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner signer, Boolean silent)
at System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer, Boolean silent)
at System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer)
at DebenuPDFSign.Program.SignData(Byte[] inputData, X509Certificate2 cert) in d:\Projects\c#\DebenuPDFSign\DebenuPDFSign\Program.cs:line 156
at DebenuPDFSign.Program.Main(String[] args) in d:\Projects\c#\DebenuPDFSign\DebenuPDFSign\Program.cs:line 102

Related

Provision device using x509 from softHSMv2

I want to provision a device using x509 security. The x509 certificate and private key are saved on an HSM. The private key cannot leave the HSM.
Ideally I'd like to pass the PKCS11 URI for both objects when creating the x509 object for transport.
const deviceCert: X509 = {
cert: cert,
clientCertEngine: "pkcs11",
keyFile: 'pkcs11:object=privateKey;type=private?pin-value=1234',
};
const securityClient = new X509Security(this.registrationId, deviceCert);
this.provisioningClient = ProvisioningDeviceClient.create(
this.provisioningHost,
this.idScopeOperator,
new ProvisioningTransport(),
securityClient
);

convert x509 ECDSA .pem cert and key to pkcs12

Is it possible to do the same as openssl does with chilkat as below:
I have tried few methods with chilkat but when I try to use it for signing a PDF file it fails.
However if I do convert it with openssl as below it passes
*** ECDSA
# Generate self-signed certificate with ECDSA using two common curves
openssl req -x509 -nodes -days 3650 -newkey ec:<(openssl ecparam -name prime256v1) -keyout ecdsakey.pem -out ecdsacert.pem
# print private and public key + curve name
openssl ec -in ecdsakey.pem -text -noout
# print certificate
openssl x509 -in ecdsacert.pem -text -noout
# generate container
openssl pkcs12 -export -inkey ecdsakey.pem -in ecdsacert.pem -out ecdsacred.p12
My certificate info looks as below:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
5a:ed:46:91:6c:d6:d4:e2:89:14:47:4c:39:62:e8:80:e4:17:e9:3b
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = IE, ST = Dublin, O = AID:Tech, OU = Blockchain, CN = ca
Validity
Not Before: Mar 31 21:10:00 2020 GMT
Not After : Mar 31 21:15:00 2021 GMT
Subject: OU = client, CN = john doe
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:91:f4:62:5b:79:31:59:41:d3:ff:59:8a:41:22:
06:13:34:5e:ce:0a:3f:16:ea:e7:91:fe:53:4f:a3:
ea:63:f7:90:aa:a3:66:72:98:97:01:2a:a6:33:b7:
c2:97:55:bf:83:b4:ca:b4:8e:6f:95:70:1f:da:f7:
f5:a4:00:77:ad
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
5E:79:09:10:5D:64:BF:68:D7:29:AC:2A:BC:BB:39:2D:FF:12:D7:37
X509v3 Authority Key Identifier:
keyid:87:4B:D2:9C:83:32:05:97:CD:93:7A:25:B7:46:39:DF:AE:19:DE:79
1.2.3.4.5.6.7.8.1:
{"attrs":{"hf.Affiliation":"","hf.EnrollmentID":"john doe","hf.Type":"client"}}
Signature Algorithm: ecdsa-with-SHA256
30:44:02:20:3c:ff:16:5f:58:c9:4b:6f:d3:7e:75:b4:68:60:
07:a3:f7:8e:d8:0f:29:52:ee:86:8f:35:46:d0:a1:d0:f1:ea:
02:20:47:ff:19:02:7a:58:d4:6d:e4:67:4a:ca:c4:67:54:90:
48:8c:b0:70:29:77:97:bb:52:2f:80:7f:5a:e8:d2:0d
Here is method 1 that I tried:
const chilkat = require('#chilkat/ck-node12-macosx');
const os = require('os');
const fs = require('fs')
function chilkatExample() {
var cert = new chilkat.Cert();
var privKey = new chilkat.PrivateKey();
// Load any type of certificate (.cer, .p7b, .pem, etc.) by calling LoadFromFile.
var success = cert.LoadFromFile("static/johnDoeCert.pem");
if (success !== true) {
console.log(cert.LastErrorText);
return;
}
// Load the private key.
// (The various privKey methods that load from a file will automatically detect
// the format. It doesn't actually matter if you try to load a non-PKCS8 format private key
// by calling LoadPkcs8EncryptedFile -- internally Chilkat will detect the format and will load
// based on what it finds.)
success = privKey.LoadPkcs8EncryptedFile("static/privKey.pem","");
if (success !== true) {
console.log(privKey.LastErrorText);
return;
}
// Write the cert as PEM.
success = cert.ExportCertPemFile("qa_output/cert.pem");
// Or get the PEM string directly...
console.log(cert.ExportCertPem());
// Associate the private key with the cert object.
success = cert.SetPrivateKey(privKey);
if (success !== true) {
console.log(cert.LastErrorText);
return;
}
// Write the cert + private key to a .pfx file.
success = cert.ExportToPfxFile("static/myPfx.p12","", true);
if (success !== true) {
console.log(cert.LastErrorText);
return;
}
console.log("Success.");
}
chilkatExample();
And here is method 2 that I tried:
const os = require('os');
const fs = require('fs')
try {
const chilkat = require('#chilkat/ck-node12-macosx');
const CERT = new chilkat.Cert();
const encodedCert = fs.readFileSync('./static/johnDoeCert.pem', { encoding: 'base64' });
const loadedCert = CERT.LoadFromBase64(encodedCert);
if (!loadedCert) {
console.log('failed to load cert')
}
const certChain = CERT.GetCertChain();
if (!CERT.LastMethodSuccess){
console.log('failed to load cert chain')
}
const PRIVKEY = new chilkat.PrivateKey()
const encodedPrivKey = fs.readFileSync('./static/privKey.pem', 'utf8');
const loadedKEy = PRIVKEY.LoadPkcs8EncryptedFile('./static/privKey.pem', "");
if (!loadedKEy) {
console.log('failed to load privagte key')
}
const PFX = new chilkat.Pfx()
const loadedPFX = PFX.AddPrivateKey(PRIVKEY, certChain)
if (!loadedPFX) {
console.log('could not load PFX')
}
const writeP12 = PFX.ToFile("", "./static/johnDoe.p12")
if (!writeP12){
console.log('could not write PFX')
}
} catch (error) {
console.log(error)
}
Thank you!
It seems that `method 1 from above works fine, my problem was on another part of my code that is not related to this.
I did slight modifications to the code above and here is my final result:
const os = require('os');
const fs = require('fs')
const chilkat = require('#chilkat/ck-node12-macosx');
try {
const CERT = new chilkat.Cert();
const PRIVKEY = new chilkat.PrivateKey()
const loadedCert = CERT.LoadFromFile('./static/cert.pem');
if (!loadedCert) {
console.log('failed to load cert')
}
const loadedKEy = PRIVKEY.LoadPkcs8EncryptedFile('./static/privKey.pem', "");
if (!loadedKEy) {
console.log('failed to load privagte key')
}
// Associate the private key with the cert object.
const associatePrivKey = CERT.SetPrivateKey(PRIVKEY);
if (!associatePrivKey) {
console.log(CERT.LastErrorText);
return;
}
// Write the cert + private key to a .pfx file.
const exported = CERT.ExportToPfxFile("static/cert.p12", "password", false);
if (!exported) {
console.log(CERT.LastErrorText);
return;
}
console.log("Success.");
} catch (error) {
console.log(error)
}

error:0409A06E:rsa routines data too large for key size

I'm generating a SAML response and it needs to be encrypted and signed with public and private keys. I generated private.pem and public.pem in the terminal with the commands
openssl genrsa -out private.pem 2048
openssl rsa -in ./private.pem -pubout -out public.pem
Then in nodeJS.
encrypt: function(message) {
return new Promise(function (resolve, reject) {
var publicKey = require("fs").readFileSync(__dirname + "/public.pem", "utf8");
var encrypted = require("crypto").publicEncrypt(publicKey, new Buffer(message));
resolve(encrypted.toString("base64"));
});
},
Once I call the message encrypt(xml), I get the following error
{
library: 'rsa routines',
function: 'RSA_padding_add_PKCS1_OAEP_mgf1',
reason: 'data too large for key size',
code: 'ERR_OSSL_RSA_DATA_TOO_LARGE_FOR_KEY_SIZE'
}
Objective:
I've to sign the message as per the demo here samltools.com (Mode: SignMessage), my SAML message looks like this. (see SAML Response section).
Sign the message
Base64Encode the message
The problem here is that you cannot directly encrypted with RSA, a piece of data which is larger than the key size.
Surprising I know, it surprised me too.
In reality very little payload data is encrypted directly with RSA or even elliptic curves.
You should be using RSA Diffie-Hellman to generate a shared secret.
Signature of the file, is really signature of the hash of the file.

Is it possible to verify and sign data in Node.js "native" (without using external call to OpenSSL)?

I have tried to find any package or solution to do a S/MIME sign/verify signature in Node.js but only found solutions using external calls (child process) to OpenSSL.
I need to run my code in AWS Lambda as Node.js so calling OpenSSL binary is not an option...
Is it at all possible to verify and sign X.509 pkcs7-signature S/MIME (Base64) signatures using only Node.js?
Sample public key:
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIIKHUtBJ7PgSwwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UE
BhMCU0UxEjAQBgNVBAcMCVN0b2NraG9sbTEMMAoGA1UECgwDQVMyMRUwEwYDVQQD
DAx0ZXN0LmFzMi5uZXQwHhcNMTgwMzE0MTI1MTAzWhcNMTkwMzE0MTI1MTAzWjBG
MQswCQYDVQQGEwJTRTESMBAGA1UEBwwJU3RvY2tob2xtMQwwCgYDVQQKDANBUzIx
FTATBgNVBAMMDHRlc3QuYXMyLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALXXVK5jP9H9JjOe9Iiba1235Xz/WuFUVP5I2Pl1ClkvGlUZRIQrje7K
Ar3OBuh8iOiNko+HuWXN505WvmiVESH9mrSSfXHDUU+JcCDkbNLDFJKiEAeZni6f
cTMMU7eWL/ZwVvAaOVXIjCC6l+nf6+rI9HNIKUpr96iIWDUMot5PQURFNUEg0OQ4
HFsuXtrm8CvbD/v3dj/2nke+HzIra27+2v3hFFP0EPCRz4+okh3a6pWrXnozrmRn
e+FFRH8mq0N0UH1AtiArDpCspnZJEGsquvj2/ruSHCarQpOS12MfPY6uFlGym3fZ
H1AxpDn11KIC3L3iNAMNCh7DWtxyrbcCAwEAAaOBtDCBsTAMBgNVHRMEBTADAQH/
MB0GA1UdDgQWBBTOWGctZLOpraEmeF77hpPcbHzbZzB1BgNVHSMEbjBsgBTOWGct
ZLOpraEmeF77hpPcbHzbZ6FKpEgwRjELMAkGA1UEBhMCU0UxEjAQBgNVBAcMCVN0
b2NraG9sbTEMMAoGA1UECgwDQVMyMRUwEwYDVQQDDAx0ZXN0LmFzMi5uZXSCCCh1
LQSez4EsMAsGA1UdDwQEAwICvDANBgkqhkiG9w0BAQsFAAOCAQEAQNhK/jVm6PRd
ui2ptx0wLd4QD7duPxULfYdhbab+Odp/LbQ08Mp1FZ8JjnJnH/z1H7SH4kPjEHIC
22VDvK1+MAjTq4iPKgpmtBSdC8dJ/S8rNE9nzpfuheM79ES8ERPNTi2Mumq1OM8L
43J+LMVwNyWx4JlI7egJgqzP5NKaPo35pI1Z/71eVGn6uPwlOdP9s8unwtOYSGZ+
mVUwQ/wiGuJ7VsxCeGPpG2rV38zUGQGiOqerkqHCLDL2K3ondA53M/myAhA7M2qP
BNPee9guEEXiI/W038rzPVSE8lETbNEnsTLxCI1uN68tEBRSZlBQwu/r/pOXP3fw
/HaEGP0gsQ==
-----END CERTIFICATE-----
Sample message signed with the matching Private Key:
This is an S/MIME signed message
------FF336B91207E7B459FAC35C0D274B8F8
Content-Type: text/plain
UNB+UNOC:3+esab+postnet+111101:1954+6045++++++'UNH+12011+INVOIC:D:93A:UN:EDIT30'BGM+380::9+006124412+9'DTM+137:20111101:102'UNT+55+12011'UNZ+1+6045'
------FF336B91207E7B459FAC35C0D274B8F8
Content-Type: application/pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
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
------FF336B91207E7B459FAC35C0D274B8F8--
Yes, it is possible with a combination of crypto and node-forge!
function verify() {
var crypto = require('crypto');
// pkg_sig is the extracted Signature from the S/MIME
// with added -----BEGIN PKCS7----- around it
var msg = pkcs7.messageFromPem(pkg_sig);
var sig = msg.rawCapture.signature;
// pkg is the "clean" signed data from the S/MIME
var buf = new Buffer(pkg, 'binary');
var verifier = crypto.createVerify("RSA-SHA256");
verifier.update(buf);
var verified = verifier.verify(cert, sig, 'binary');
console.log(verified);
}
function sign() {
/*
// Verified working AW, 2018-03-15
// Signature successfully verified by OPENSSL
openssl smime -verify -in packageCopy.txt -CAfile test.as2.net-sscert.pem
Content-Type: text/plain
UNB+UNOC:3+esab+postnet+111101:1954+6045++++++'UNH+12011+INVOIC:D:93A:UN:EDIT30'BGM+380::9+006124412+9'DTM+137:20111101:102'UNT+55+12011'UNZ+1+6045' Verification successful
*/
var p7 = pkcs7.createSignedData();
p7.content = forge.util.createBuffer(pkg);
p7.addCertificate(cert);
p7.addSigner({
key: forge.pki.privateKeyFromPem(key),
certificate: cert,
digestAlgorithm: forge.pki.oids.sha256
});
p7.sign();
var pem = pkcs7.messageToPem(p7);
console.log(pem);
}

Programmatically create certificate and certificate key in Node

Using node.js, I'd like to write code to programmatically do the equivalent of the following:
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
openssl rsa -passin pass:x -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
When complete, I need the RSA key server.key and the self-signed SSL certificate server.crt.
forge looks the most promising, but so far I haven't figured out how to get it to work. I have the following code:
var pki = forge.pki;
var keys = pki.rsa.generateKeyPair(2048);
var privKey = forge.pki.privateKeyToPem(keys.privateKey);
var pubKey = forge.pki.publicKeyToPem(keys.publicKey);
But when I write the pubKey to a file, I've noticed it starts with ...
-----BEGIN PUBLIC KEY-----
MIIB...
-----END PUBLIC KEY-----
... and isn't recognized, whereas using openssl above it starts with:
-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----
Since the original link went dead, I've made my own code that generates a self-signed certificate using node-forge (which it looks like they already have based on the original question), so I thought I'd put it here for someone who wants it
Simply creating a public and private key pair isn't enough to work as a certificate, you have to put in attributes, node-forge is incredibly useful this way, as its pki submodule is designed for this.
First, you need to create a certificate via pki.createCertificate(), this is where you'll assign all of your certificate attributes.
You need to set the certificate public key, serial number, and the valid from date and valid to date. In this example, the public key is set to the generated public key from before, the serial number is randomly generated, and the valid from and to dates are set to one day ago and one year in the future.
You then need to assign a subject, and extensions to your certificate, this is a very basic example, so the subject is just a name you can define (or let it default to 'Testing CA - DO NOT TRUST'), and the extensions are just a single 'Basic Constraints' extension, with certificate authority set to true.
We then set the issuer to itself, as all certificates need an issuer, and we don't have one.
Then we tell the certificate to sign itself, with the private key (corresponding to its public key we've assigned) that we generated earlier, this part is important when signing certificates (or child certificates), they need to be signed with the private key of its parent (this prevents you from making fake certificates with a trusted certificate parent, as you don't have that trusted parent's private key)
Then we return the new certificate in a PEM-encoded format, you could save this to a file or convert it to a buffer and use it for a https server.
const forge = require('node-forge')
const crypto = require('crypto')
const pki = forge.pki
//using a blank options is perfectly fine here
async function genCACert(options = {}) {
options = {...{
commonName: 'Testing CA - DO NOT TRUST',
bits: 2048
}, ...options}
let keyPair = await new Promise((res, rej) => {
pki.rsa.generateKeyPair({ bits: options.bits }, (error, pair) => {
if (error) rej(error);
else res(pair)
})
})
let cert = pki.createCertificate()
cert.publicKey = keyPair.publicKey
cert.serialNumber = crypto.randomUUID().replace(/-/g, '')
cert.validity.notBefore = new Date()
cert.validity.notBefore.setDate(cert.validity.notBefore.getDate() - 1)
cert.validity.notAfter = new Date()
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1)
cert.setSubject([{name: 'commonName', value: options.commonName}])
cert.setExtensions([{ name: 'basicConstraints', cA: true }])
cert.setIssuer(cert.subject.attributes)
cert.sign(keyPair.privateKey, forge.md.sha256.create())
return {
ca: {
key: pki.privateKeyToPem(keyPair.privateKey),
cert: pki.certificateToPem(cert)
},
fingerprint: forge.util.encode64(
pki.getPublicKeyFingerprint(keyPair.publicKey, {
type: 'SubjectPublicKeyInfo',
md: forge.md.sha256.create(),
encoding: 'binary'
})
)
}
}
//you need to put the output from genCACert() through this if you want to use it for a https server
/* e.g
let cert = await genCACert();
let buffers = caToBuffer(cert.ca);
let options = {};
options.key = buffers.key;
options.cert = buffers.cert;
let server = https.createServer(options, <listener here>);
*/
function caToBuffer(ca) {
return {
key: Buffer.from(ca.key),
cert: Buffer.from(ca.cert)
}
}
Do with this what you will.
Okay, as you probably realized, I wasn't generating a certificate. It required quite a bit more work, which you can find here.
Essentially, after a bunch of setup, I had to create, sign, and convert the certificate to Pem:
cert.sign(keys.privateKey);
var pubKey = pki.certificateToPem(cert);
Hope this helps someone else!

Resources