Skip to content

Commit

Permalink
Merge pull request #529 from cplussharp/x509-jwk
Browse files Browse the repository at this point in the history
JWK from X509 certificate
  • Loading branch information
kjur authored Nov 29, 2021
2 parents 6bf4f0e + 2f84eb3 commit 6553edf
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/x509-1.1.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,26 @@ function X509(params) {
return KEYUTIL.getKey(this.getPublicKeyHex(), null, "pkcs8pub");
};

/**
* get a JSON Web Key object of the public key, including the certificate itself<br/>
* @name getPublicKeyJWK
* @memberOf X509#
* @function
* @return {Object} JSON Web Key object of the certificate
* @example
* x = new X509();
* x.readCertPEM(sCertPEM);
* jwk = x.getPublicKeyJWK();
*/
this.getPublicKeyJWK = function() {
var key = this.getPublicKey();
var jwk = KEYUTIL.getJWKFromKey(key);
jwk.x5c = [hex2b64(this.hex)];
jwk.x5t = b64tob64u(hex2b64(KJUR.crypto.Util.hashHex(this.hex, "sha1")));
jwk["x5t#S256"] = b64tob64u(hex2b64(KJUR.crypto.Util.hashHex(this.hex, "sha256")));
return jwk;
};

/**
* get signature algorithm name from hexadecimal certificate data
* @name getSignatureAlgorithmName
Expand Down Expand Up @@ -2268,6 +2288,20 @@ function X509(params) {
this.readCertHex(_pemtohex(sCertPEM));
};

/**
* read X.509 certificate from JWK object.<br/>
* @name readCertJWK
* @memberOf X509#
* @function
* @param {Object} oJwk JSON Web Key object containing a "x5c" member
* @example
* x = new X509();
* x.readCertJWK(oJwk); // read certificate
*/
this.readCertJWK = function(oJwk) {
this.readCertHex(b64tohex(oJwk.x5c[0]));
};

/**
* read a hexadecimal string of X.509 certificate<br/>
* @name readCertHex
Expand Down
1 change: 1 addition & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<li><a href="qunit-do-x509-ext.html">qunit-do-x509-ext.html</a></li>
<li><a href="qunit-do-x509-getinfo.html">qunit-do-x509-getinfo.html</a></li>
<li><a href="qunit-do-x509-hex2dn.html">qunit-do-x509-hex2dn.html</a></li>
<li><a href="qunit-do-x509-jwk.html">qunit-do-x509-jwk.html</a></li>
<li><a href="qunit-do-x509-key.html">qunit-do-x509-key.html</a></li>
<li><a href="qunit-do-x509-kid.html">qunit-do-x509-kid.html</a></li>
<li><a href="qunit-do-x509-param.html">qunit-do-x509-param.html</a></li>
Expand Down
158 changes: 158 additions & 0 deletions test/qunit-do-x509-jwk.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>QUnit for JWK of X.509 Certificate 'x509.js'</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="qunit.js"></script>
<link rel="stylesheet" href="qunit.css" type="text/css" media="screen" />

<script src="../ext/cj/cryptojs-312-core-fix.js"></script>
<script src="../ext/cj/x64-core.js"></script>
<script src="../ext/cj/cipher-core_min.js"></script>
<script src="../ext/cj/aes_min.js"></script>
<script src="../ext/cj/tripledes_min.js"></script>
<script src="../ext/cj/enc-base64_min.js"></script>
<script src="../ext/cj/md5_min.js"></script>
<script src="../ext/cj/sha1_min.js"></script>
<script src="../ext/cj/sha256_min.js"></script>
<script src="../ext/cj/sha224_min.js"></script>
<script src="../ext/cj/sha512_min.js"></script>
<script src="../ext/cj/sha384_min.js"></script>
<script src="../ext/cj/ripemd160_min.js"></script>
<script src="../ext/cj/hmac_min.js"></script>
<script src="../ext/cj/pbkdf2_min.js"></script>

<script src="../ext/jsbn.js"></script>
<script src="../ext/jsbn2.js"></script>
<script src="../ext/rsa.js"></script>
<script src="../ext/rsa2.js"></script>
<script src="../ext/base64.js"></script>
<script src="../ext/prng4.js"></script>
<script src="../ext/rng.js"></script>
<script src="../ext/ec.js"></script>
<script src="../ext/ec-patch.js"></script>

<script src="../src/base64x-1.1.js"></script>
<script src="../src/asn1hex-1.1.js"></script>
<script src="../src/crypto-1.1.js"></script>
<script src="../src/rsapem-1.1.js"></script>
<script src="../src/x509-1.1.js"></script>
<script src="../src/keyutil-1.0.js"></script>
<script src="../src/ecdsa-modified-1.0.js"></script>
<script src="../src/ecparam-1.0.js"></script>

<script type="text/javascript">
$(document).ready(function(){

// RSA Cert
var z1CertPEM = "" +
"-----BEGIN CERTIFICATE-----\n" +
"MIIBdTCCAR+gAwIBAgIBBTANBgkqhkiG9w0BAQUFADAaMQswCQYDVQQGEwJVUzEL\n" +
"MAkGA1UECgwCYTEwHhcNMTMwNTA0MDM0MTQxWhcNMjMwNTA0MDM0MTQxWjAaMQsw\n" +
"CQYDVQQGEwJVUzELMAkGA1UECgwCYTEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA\n" +
"6GZN0rQFKRIVaPOzm8l6Yue6PAm6vcTw3NjfkOt5C5u2RaK3DjESdHtNPEG1FCSJ\n" +
"URX++I951D6uWxpONRj9WQIDAQABo1AwTjAdBgNVHQ4EFgQUxUc+4gDI561wA9/1\n" +
"QguM3fTCDhUwHwYDVR0jBBgwFoAUxUc+4gDI561wA9/1QguM3fTCDhUwDAYDVR0T\n" +
"BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBALL2k69LjwOYfDXv3TXJUAFGUqto+Noj\n" +
"CJLP08fOfNBZy+KAIy0GsrNU/3uRViqbuGqAnH9kFFwHQjOAFrAe8XQ=\n" +
"-----END CERTIFICATE-----\n";

var z1CertJwk = {
"kty": "RSA",
"e": "AQAB",
"n": '6GZN0rQFKRIVaPOzm8l6Yue6PAm6vcTw3NjfkOt5C5u2RaK3DjESdHtNPEG1FCSJURX--I951D6uWxpONRj9WQ',
"x5c": ["MIIBdTCCAR+gAwIBAgIBBTANBgkqhkiG9w0BAQUFADAaMQswCQYDVQQGEwJVUzELMAkGA1UECgwCYTEwHhcNMTMwNTA0MDM0MTQxWhcNMjMwNTA0MDM0MTQxWjAaMQswCQYDVQQGEwJVUzELMAkGA1UECgwCYTEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA6GZN0rQFKRIVaPOzm8l6Yue6PAm6vcTw3NjfkOt5C5u2RaK3DjESdHtNPEG1FCSJURX++I951D6uWxpONRj9WQIDAQABo1AwTjAdBgNVHQ4EFgQUxUc+4gDI561wA9/1QguM3fTCDhUwHwYDVR0jBBgwFoAUxUc+4gDI561wA9/1QguM3fTCDhUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBALL2k69LjwOYfDXv3TXJUAFGUqto+NojCJLP08fOfNBZy+KAIy0GsrNU/3uRViqbuGqAnH9kFFwHQjOAFrAe8XQ="],
"x5t": "UA2-H4laZVxA0yjgdsv6pQeJjDo",
"x5t#S256": "ZWjlGMDlS2Exn5a3WbEQ-4Ez935ZVY8UJsjUKs3LKwo"
};

// EC Cert
var k6CertPem = "" +
"-----BEGIN CERTIFICATE-----\n" +
"MIIBrjCCATWgAwIBAgIBATAJBgcqhkjOPQQBMBoxCzAJBgNVBAYTAlVTMQswCQYD\n" +
"VQQKDAJLNjAeFw0xMzA4MjgxODI2MDNaFw0yMzA4MjgxODI2MDNaMBoxCzAJBgNV\n" +
"BAYTAlVTMQswCQYDVQQKDAJLNjB2MBAGByqGSM49AgEGBSuBBAAiA2IABFQ1Jqvf\n" +
"xHOUo/JkWw1IZRqfOk1G2HQL4yKRUQfwUCUMcwykCzfh3IXggrS7GBuIR71tD6J4\n" +
"uuXrHAVHTJpOK+7CjJcL5JwZSfCelpeaJ3pRSDDjKlud4exoq5n0kt0wCqNQME4w\n" +
"HQYDVR0OBBYEFDr7X/HKjspl4kCJ9a8zWed/DZHrMB8GA1UdIwQYMBaAFDr7X/HK\n" +
"jspl4kCJ9a8zWed/DZHrMAwGA1UdEwQFMAMBAf8wCQYHKoZIzj0EAQNoADBlAjEA\n" +
"jteX+S/Btn1akjFeWf35iEbFpT9iPRxPZbUrCaEYBycyemCRTQslG5fxys9OGTtC\n" +
"AjB+9NmIQ5QtTgDDiZf6SaeDosq81aU/1S8eOdD/7H9SdclILyo93+i+S9qDio75\n" +
"2F8=\n" +
"-----END CERTIFICATE-----\n";

var k6CertJwk = {
"kty": "EC",
"crv": "P-384",
"x": 'VDUmq9_Ec5Sj8mRbDUhlGp86TUbYdAvjIpFRB_BQJQxzDKQLN-HcheCCtLsYG4hH',
"y": 'vW0Poni65escBUdMmk4r7sKMlwvknBlJ8J6Wl5onelFIMOMqW53h7GirmfSS3TAK',
"x5c": ["MIIBrjCCATWgAwIBAgIBATAJBgcqhkjOPQQBMBoxCzAJBgNVBAYTAlVTMQswCQYDVQQKDAJLNjAeFw0xMzA4MjgxODI2MDNaFw0yMzA4MjgxODI2MDNaMBoxCzAJBgNVBAYTAlVTMQswCQYDVQQKDAJLNjB2MBAGByqGSM49AgEGBSuBBAAiA2IABFQ1JqvfxHOUo/JkWw1IZRqfOk1G2HQL4yKRUQfwUCUMcwykCzfh3IXggrS7GBuIR71tD6J4uuXrHAVHTJpOK+7CjJcL5JwZSfCelpeaJ3pRSDDjKlud4exoq5n0kt0wCqNQME4wHQYDVR0OBBYEFDr7X/HKjspl4kCJ9a8zWed/DZHrMB8GA1UdIwQYMBaAFDr7X/HKjspl4kCJ9a8zWed/DZHrMAwGA1UdEwQFMAMBAf8wCQYHKoZIzj0EAQNoADBlAjEAjteX+S/Btn1akjFeWf35iEbFpT9iPRxPZbUrCaEYBycyemCRTQslG5fxys9OGTtCAjB+9NmIQ5QtTgDDiZf6SaeDosq81aU/1S8eOdD/7H9SdclILyo93+i+S9qDio752F8="],
"x5t": "qs3xobcwmaHC1zuZ9GaD4Cjga80",
"x5t#S256": "Jg6rIIYsbkuh641caFsEXhwXQB-km3MtQZUG5dnkuWE"
};

test("getPublicKeyJWK() RSA", function() {
var x = new X509();
x.readCertPEM(z1CertPEM);
var key = x.getPublicKeyJWK();
equal(key.kty, z1CertJwk.kty, "key type");
equal(key.n, z1CertJwk.n, "n");
equal(key.e, z1CertJwk.e, "e");
equal(key.x5c.length, 1, "x5c.length");
equal(key.x5c[0], z1CertJwk.x5c[0], "x5c[0]");
equal(key.x5t, z1CertJwk.x5t, "x5t");
equal(key["x5t#S256"], z1CertJwk["x5t#S256"], "x5t#S256");
});

test("getPublicKeyJWK() EC", function() {
var x = new X509();
x.readCertPEM(k6CertPem);
var key = x.getPublicKeyJWK();
equal(key.kty, k6CertJwk.kty, "key type");
equal(key.crv, k6CertJwk.crv, "curve");
equal(key.x, k6CertJwk.x, "x");
equal(key.y, k6CertJwk.y, "y");
equal(key.x5c.length, 1, "x5c.length");
equal(key.x5c[0], k6CertJwk.x5c[0], "x5c[0]");
equal(key.x5t, k6CertJwk.x5t, "x5t");
equal(key["x5t#S256"], k6CertJwk["x5t#S256"], "x5t#S256");
});

test("readCertJWK() RSA", function() {
var x = new X509();
x.readCertJWK(z1CertJwk);
var key = x.getPublicKeyJWK();
equal(key.x5c[0], z1CertJwk.x5c[0], "x5c[0]");
});

test("readCertJWK() EC", function() {
var x = new X509();
x.readCertJWK(k6CertJwk);
var key = x.getPublicKeyJWK();
equal(key.x5c[0], k6CertJwk.x5c[0], "x5c[0]");
});

});
</script>

</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture">test markup</div>

<p>
<a href="../">TOP</a> |
<a href="index.html">TEST INDEX</a> |
<a href="qunit-do-x509.html">x509</a> |
<a href="qunit-do-x509-ext.html">x509-ext</a> |
<a href="qunit-do-x509-key.html">x509-key</a> |
<a href="qunit-do-x509-kid.html">x509-kid</a> |
<a href="qunit-do-x509-getinfo.html">x509-getinfo</a> |
<a href="qunit-do-x509-v1.html">x509-v1</a> |
</p>

</body>
<center><p>&copy; 2010-2021 Kenji Urushima</p></center>
</html>

0 comments on commit 6553edf

Please sign in to comment.