X.509 certificate generation with RSA or ECDSA signing in JavaScript
This page will generate either RSA and ECC key pairs, and then generate X.509 certificates, using either a signature of SHA1withRSA or SHA256withECDSA. For RSA signing we use an RSA private key to sign the certificate, and with ECDSA signing we use an ECC private key to sign the certificate.
Method |
RSA: ECC: |
---|---|
Private Key (scroll of more details) | |
Public Key (scroll of more details) | |
X509 |
Theory
Now, what is one of the most important things in cybersecurity, but is one of the least understood things? Well, I think it is digital certificates, and how they integrate into PKI (Public Key Infrastructure). Go ask a cybersecurity professional about how digital certificates are created and used, and it's likely that they will struggle to explain them fully. But, overall, they basically hold a trusted public key of an entity, and which has been validated by another entity which is generally trusted.
If Alice wants to prove herself to Bob, she digitally signs a message with her private key, and where Bob can prove this signature using her public key. For this, we need Trent to sign a digital certificate with Bob's public key, and he will then use his private key to do this. Bob then checks the signature on this certificate using Trent's public key. If Bob trusts that Trent has checked Alice's public key, he can trust the public key from the certificate. Trent's public key can then be installed onto Bob's computer as a root certificate. If Bob finds that Trent's private key has been compromised, he can then revoke its trust. I have created a Doodle here:
But, we have many different operating systems and devices. So, how can we create digital certificates which can be ported onto any system? Well, the magic of this is defined in X.509, and which was initially defined by the ISO in 1988 - as part of their OSI (Open System Integration) approach. The focus of X.509 is to bind a given identity to a public key and thus prove digital signatures. Their basic structure is based on Abstract Syntax Notation One (ASN.1). To advance their adoption, the X.509 format was further standardized on the Internet with RFC 3279 [1]:
The two main digital signing methods used are with RSA and ECDSA signatures. We also define the hashing method used, such as SHA1 and SHA256. For hashing, SHA256 is preferred, as it is more secure. Other signing methods include DSA (which uses discrete log methods) and Ed25519 (which uses Curve 25519 for digital signing).
We can add many elements to a digital certificate, including:
Version Number Serial Number Signature Algorithm ID Issuer Name Validity Not Before Validity Not After Subject name Public Key Algorithm Subject Public Key Certificate Signature Algorithm Certificate Signature
These elements can be matched to the requirement, such as for the subject and the issuer's common name. An important element is a date that the certificate is valid from (Validity Not Before) and to (Validity Not After). A certificate which has a validity date not after that is before the current date is likely to be marked as untrusted.
If we look at a Google.com certificate, we can see some of these elements, including the subject and issuer name. This format includes CN (Common Name), O (Organisation) and C (Country):
Coding
Some JavaScript coding for creating an X.509 certificate is:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/10.5.26/jsrsasign-all-min.js"></script> <script type="text/javascript">document.getElementById("m").value = "Hello"; function gorsa(size) { var kp = KEYUTIL.generateKeypair("RSA", size); var priv = KEYUTIL.getPEM(kp.prvKeyObj, "PKCS8PRV"); var privhex = pemtohex(priv); var privasn1 = ASN1HEX.dump(pemtohex(priv)); document.getElementById("privatekey").innerHTML = priv; document.getElementById("privatekey").innerHTML += "\n\nHex:\n" + privhex; document.getElementById("privatekey").innerHTML += "\n\nASN1:\n" + privasn1; pub = KEYUTIL.getPEM(kp.pubKeyObj, "PKCS8PUB"); var pubhex = pemtohex(pub); var pubasn1 = ASN1HEX.dump(pemtohex(pub)); document.getElementById("publickey").innerHTML = pub; document.getElementById("publickey").innerHTML += "\n\nHex:\n" + pubhex; document.getElementById("publickey").innerHTML += "\n\nASN1:\n" + pubasn1; var x = new KJUR.asn1.x509.Certificate({ version: 3, serial: { int: 4 }, issuer: { str: "/CN=ASecuritysite" }, notbefore: "151231235959Z", notafter: "251231235959Z", subject: { str: "/CN=Web server" }, sbjpubkey: kp.pubKeyObj, ext: [ { extname: "basicConstraints", cA: false }, { extname: "keyUsage", critical: true, names: ["digitalSignature"] }, { extname: "cRLDistributionPoints", array: [{ fulluri: 'http://bob.asecuritysite.com/' }] } ], sigalg: "SHA1withRSA", cakey: kp.prvKeyObj }); document.getElementById("X509").innerHTML = "RSA Signed Certificate [SHA1withRSA]: (" +size+" bits)\n" +x.getPEM(); var certasn1 = ASN1HEX.dump(pemtohex(x.getPEM())); document.getElementById("X509").innerHTML += "\nASN.1:\n" + certasn1; } function goecc(name) { var kp = KEYUTIL.generateKeypair("EC", name); var priv = KEYUTIL.getPEM(kp.prvKeyObj, "PKCS8PRV"); var privhex = pemtohex(priv); var privasn1 = ASN1HEX.dump(pemtohex(priv)); document.getElementById("privatekey").innerHTML = priv; document.getElementById("privatekey").innerHTML += "\n\nHex:\n" + privhex; document.getElementById("privatekey").innerHTML += "\n\nASN1:\n" + privasn1; pub = KEYUTIL.getPEM(kp.pubKeyObj, "PKCS8PUB"); var pubhex = pemtohex(pub); var pubasn1 = ASN1HEX.dump(pemtohex(pub)); document.getElementById("publickey").innerHTML = pub; document.getElementById("publickey").innerHTML += "\n\nHex:\n" + pubhex; document.getElementById("publickey").innerHTML += "\n\nASN1:\n" + pubasn1; var x = new KJUR.asn1.x509.Certificate({ version: 3, serial: { int: 4 }, issuer: { str: "/CN=ASecuritysite" }, notbefore: "151231235959Z", notafter: "251231235959Z", subject: { str: "/CN=Web server" }, sbjpubkey: kp.pubKeyObj, ext: [ { extname: "basicConstraints", cA: false }, { extname: "keyUsage", critical: true, names: ["digitalSignature"] }, { extname: "cRLDistributionPoints", array: [{ fulluri: 'http://bob.asecuritysite.com/' }] } ], sigalg: "SHA256withECDSA", cakey: kp.prvKeyObj }); document.getElementById("X509").innerHTML = "ECC Certificate [SHA256withECDSA]: ("+name+")\n" + x.getPEM(); var certasn1 = ASN1HEX.dump(pemtohex(x.getPEM())); document.getElementById("X509").innerHTML += "\nASN.1:\n" + certasn1; }</script>
The HTML is then:
<div class="indented"> <table width="100%"> <tr> <th valign="top">Method</th> <td style="text-align:left"> <p> RSA: <input type="button" class="btn btn-medium btn-success" onclick="gorsa(512)" value="Generate RSA 512"><input type="button" class="btn btn-medium btn-success" onclick="gorsa(1024)" value="Generate RSA 1024"> </p> <p> ECC: <input type="button" class="btn btn-medium btn-warning" onclick="goecc('secp256r1')" value="Secp256r1 (P-256)"> <input type="button" class="btn btn-medium btn-warning" onclick="goecc('secp256k1')" value="Secp256k1 (Ethereum)"> <input type="button" class="btn btn-medium btn-warning" onclick="goecc('secp384r1')" value="secp384r1"> </p> </td> </tr> <tr> <th valign="top" width="15%">Private Key (scroll of more details)</th> <td> <textarea cols="20" id="privatekey" name="privatekey" rows="5" style="width:100%"></textarea> </td> </tr> <tr> <th valign="top">Public Key (scroll of more details)</th> <td> <textarea cols="20" id="publickey" name="publickey" rows="5" style="width:100%"></textarea> </td> </tr> <tr> <th valign="top">X509</th> <td> <textarea cols="20" id="X509" name="X509" rows="5" style="width:100%"></textarea> </td> </tr> </table> </div>
In the case. we display in a PEM and in an ASN.1 format. With PEM we have a Base64 form - which is easy to port across systems. With ASN.1 we can see the details of the certificate contents. A sample run for ECDSA is:
ECC Certificate [SHA256withECDSA]: (secp256r1) -----BEGIN CERTIFICATE----- MIIBajCCAQ+gAwIBAgIBBDAKBggqhkjOPQQDAjAYMRYwFAYDVQQDDA1BU2VjdXJp dHlzaXRlMB4XDTE1MTIzMTIzNTk1OVoXDTI1MTIzMTIzNTk1OVowFTETMBEGA1UE AwwKV2ViIHNlcnZlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCh7OEuvP2M+ zSNNYS3YDVHCGsnZjl9OvMR7SeE9x8smwyb+pN7MlUgbUqgnXT5wLi4hcxv2umF+ YXLBY3EIUaWjTTBLMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMC4GA1UdHwQn MCUwI6AhoB+GHWh0dHA6Ly9ib2IuYXNlY3VyaXR5c2l0ZS5jb20vMAoGCCqGSM49 BAMCA0kAMEYCIQCy0lpXc89dMXOnFlW1ZiZcU3J9A1SHta7p3l3WcUnokQIhANxs wkHjP2lOw5iI5bueWNG02+7VsK7aAWR1kN1W5wDL -----END CERTIFICATE-----
ASN.1: SEQUENCE SEQUENCE [0] INTEGER 02 INTEGER 04 SEQUENCE ObjectIdentifier SHA256withECDSA (1 2 840 10045 4 3 2) SEQUENCE SET SEQUENCE ObjectIdentifier commonName (2 5 4 3) UTF8String 'ASecuritysite' SEQUENCE UTCTime 151231235959Z UTCTime 251231235959Z SEQUENCE SET SEQUENCE ObjectIdentifier commonName (2 5 4 3) UTF8String 'Web server' SEQUENCE SEQUENCE ObjectIdentifier ecPublicKey (1 2 840 10045 2 1) ObjectIdentifier P-256 (1 2 840 10045 3 1 7) BITSTRING 0004287b384baf3f633ecd234d612dd8..(total 66bytes)..2e21731bf6ba617e6172c163710851a5 [3] SEQUENCE SEQUENCE ObjectIdentifier basicConstraints (2 5 29 19) OCTETSTRING, encapsulates SEQUENCE {} SEQUENCE ObjectIdentifier keyUsage (2 5 29 15) BOOLEAN TRUE OCTETSTRING, encapsulates BITSTRING 0780 SEQUENCE ObjectIdentifier cRLDistributionPoints (2 5 29 31) OCTETSTRING, encapsulates SEQUENCE SEQUENCE [0] [0] [6] http://bob.asecuritysite.com/ SEQUENCE ObjectIdentifier SHA256withECDSA (1 2 840 10045 4 3 2) BITSTRING, encapsulates SEQUENCE INTEGER 00b2d25a5773cf5d3173a71655b56626..(total 33bytes)..53727d035487b5aee9de5dd67149e891 INTEGER 00dc6cc241e33f694ec39888e5bb9e58..(total 33bytes)..b4dbeed5b0aeda01647590dd56e700cb
With ASN.1 we define an OID. In this case "1.2.840.10045.4.3.2" identifies ECDSA with SHA256 signing, and "2.5.4.3" identifies the common name of either the subject or the issuer. For an RSA signed certificate, a sample run gives [here]:
RSA Signed Certificate [SHA1withRSA]: (512 bits) -----BEGIN CERTIFICATE----- MIIBazCCARWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAYMRYwFAYDVQQDDA1BU2Vj dXJpdHlzaXRlMB4XDTE1MTIzMTIzNTk1OVoXDTI1MTIzMTIzNTk1OVowFTETMBEG A1UEAwwKV2ViIHNlcnZlcjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCoRi3EtXPk t/51SpZYa0WMa+rstDfM605BzNdRajziznusrRyxjyEQ0CMqE/+vaBy50ZkAAyKv Q4ti6w02Y/j7AgMBAAGjTTBLMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMC4G A1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly9ib2IuYXNlY3VyaXR5c2l0ZS5jb20vMA0G CSqGSIb3DQEBBQUAA0EAmvSwggR+V23TmFZ+Tf0WwzxjualDv6UPEkFx01H5oWzA pXn7cOzyGRzcgPQjE3+2KLcTTU5Fo0dRoU5hujt3SA== -----END CERTIFICATE-----
ASN.1: SEQUENCE SEQUENCE [0] INTEGER 02 INTEGER 04 SEQUENCE ObjectIdentifier SHA1withRSA (1 2 840 113549 1 1 5) NULL SEQUENCE SET SEQUENCE ObjectIdentifier commonName (2 5 4 3) UTF8String 'ASecuritysite' SEQUENCE UTCTime 151231235959Z UTCTime 251231235959Z SEQUENCE SET SEQUENCE ObjectIdentifier commonName (2 5 4 3) UTF8String 'Web server' SEQUENCE SEQUENCE ObjectIdentifier rsaEncryption (1 2 840 113549 1 1 1) NULL BITSTRING, encapsulates SEQUENCE INTEGER 00a8462dc4b573e4b7fe754a96586b45..(total 65bytes)..b9d199000322af438b62eb0d3663f8fb INTEGER 010001 [3] SEQUENCE SEQUENCE ObjectIdentifier basicConstraints (2 5 29 19) OCTETSTRING, encapsulates SEQUENCE {} SEQUENCE ObjectIdentifier keyUsage (2 5 29 15) BOOLEAN TRUE OCTETSTRING, encapsulates BITSTRING 0780 SEQUENCE ObjectIdentifier cRLDistributionPoints (2 5 29 31) OCTETSTRING, encapsulates SEQUENCE SEQUENCE [0] [0] [6] http://bob.asecuritysite.com/ SEQUENCE ObjectIdentifier SHA1withRSA (1 2 840 113549 1 1 5) NULL BITSTRING 009af4b082047e576dd398567e4dfd16..(total 65bytes)..28b7134d4e45a34751a14e61ba3b7748
References
[1] RFC 3279, Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile [here]
A list of object IDs:
Hashing: MD2 1.2.840.113549.2.2 MD5 1.2.840.113549.2.5 SHA-1 1.3.14.3.2.26 SHA-224 2.16.840.1.101.3.4.2.4 SHA-256 2.16.840.1.101.3.4.2.1 SHA-394 2.16.840.1.101.3.4.2.2 SHA-512 2.16.840.1.101.3.4.2.3 Public key: RSA Encryption 1.2.840.113549.1.1.1 DSA 1.2.840.10040.4.1 Diffie-Hellman (dhPublicNumber) 1.2.840.10046.2.1 ECC (ecPublicKey) 1.2.840.10045.2.1 md2WithRsaEncryption 1.2.840.113549.1.1.2 Signatures: md5WithRsaEncryption 1.2.840.113549.1.1.4 sha1WithRsaEncryption 1.2.840.113549.1.1.5 sha224WithRsaEncryption 1.2.840.113549.1.1.14 sha256WithRsaEncryption 1.2.840.113549.1.1.11 sha384WithRsaEncryption 1.2.840.113549.1.1.12 sha512WithRsaEncryption 1.2.840.113549.1.1.13 dsaWithSha1 1.2.840.10040.4.3 dsaWithSha224 2.16.840.1.101.3.4.3.1 dsaWithSha256 2.16.840.1.101.3.4.3.2 ecdsaWithSha1 1.2.840.10045.4.1 ecdsaWithSha224 1.2.840.10045.4.3.1 ecdsaWithSha256 1.2.840.10045.4.3.2 ecdsaWithSha384 1.2.840.10045.4.3.3 ecdsaWithSha512 1.2.840.10045.4.3.4 Password Base Encryption Algorithms: pbeWithMd2AndDesCbc 1.2.840.113549.1.5.1 pbeWithMd5AndDesCbc 1.2.840.113549.1.5.3 pbeWithSha1AndDesCbc 1.2.840.113549.1.5.10 pbeWithMd2AndRc2Cbc 1.2.840.113549.1.5.4 pbeWithMd5AndRc2Cbc 1.2.840.113549.1.5.6 pbeWithSha1AndRc2Cbc 1.2.840.113549.1.5.11 pbeWithSha1And40BitRc2Cbc 1.2.840.113549.1.12.1.6 pbeWithSha1And128BitRc2Cbc 1.2.840.113549.1.12.1.5 pbeWithSha1And40BitRc4 1.2.840.113549.1.12.1.2 pbeWithSha1And128BitRc4 1.2.840.113549.1.12.1.1 pbeWithSha1And3DesCbc 1.2.840.113549.1.12.1.3 Symmetric EncryptionAlg orithms: DES CBC 1.3.14.3.2.7 3DES CBC 1.2.840.113549.3.7 RC2 1.2.840.113549.3.2 ArcFour 1.2.840.113549.3.4 AES CBC 128 2.16.840.1.101.3.4.1.2 AES CBC 256 2.16.840.1.101.3.4.1.42x.500 Distinguished Name Attributes: name 2.5.4.41 surname 2.5.4.4 given name 2.5.4.42 initials 2.5.4.43 generation qualifier 2.5.4.44 common name 2.5.4.3 locality name 2.5.4.7 state or province name 2.5.4.8 organization name 2.5.4.10 organizational unit name 2.5.4.11 title 2.5.4.12 dnQualifier 2.5.4.46 country name 2.5.4.6 email address 1.2.840.113549.1.9.1 domain component 0.9.2342.19200300.100.1.25 street address 2.5.4.9 postal code 2.5.4.17 mail 0.9.2342.19200300.100.1.3 serial number 2.5.4.5 ECC names: secp192r1 1.2.840.10045.3.1.1 secp224r1 1.3.132.0.33 secp256r1 1.2.840.10045.3.1.7 secp384r1 1.3.132.0.34 secp521r1 1.3.132.0.35 brainpoolP160r1 1.3.36.3.3.2.8.1.1.1 brainpoolP192r1 1.3.36.3.3.2.8.1.1.3 brainpoolP224r1 1.3.36.3.3.2.8.1.1.5 brainpoolP256r1 1.3.36.3.3.2.8.1.1.7 brainpoolP320r1 1.3.36.3.3.2.8.1.1.9 brainpoolP384r1 1.3.36.3.3.2.8.1.1.11 brainpoolP512r1 1.3.36.3.3.2.8.1.1.13