1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2015 CardContact Software & System Consulting 6 * |'##> <##'| Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de) 7 * --------- 8 * 9 * This file is part of OpenSCDP. 10 * 11 * OpenSCDP is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * OpenSCDP is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with OpenSCDP; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @fileoverview PKCS#10 Decoder 25 */ 26 27 var PKIXCommon = require('scsh/x509/PKIXCommon').PKIXCommon; 28 var X509Name = require('scsh/x509/X509Name').X509Name; 29 30 31 /** 32 * Class supporting PKCS#10 certificate signing requests 33 * 34 * @param {ASN1} req the certificate request 35 */ 36 function PKCS10(req) { 37 38 if (req instanceof ASN1) { 39 this.req = req; 40 } else if (req instanceof ByteString) { 41 var asn = new ASN1(req); 42 this.req = asn; 43 } else { 44 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Argument must be either type of ByteString or ASN1"); 45 } 46 47 this.reqInfo = this.req.get(0); 48 this.sigAlg = this.req.get(1); 49 this.sig = this.req.get(2); 50 } 51 52 exports.PKCS10 = PKCS10; 53 54 PKCS10.RSA = new ByteString("rsaEncryption", OID); 55 PKCS10.RSA_PSS = new ByteString("id-RSASSA-PSS", OID); 56 PKCS10.EC = new ByteString("id-ecPublicKey", OID); 57 58 59 60 /** 61 * Get the encoded request 62 * 63 * @return the encoded request 64 * @type ByteString 65 */ 66 PKCS10.prototype.getBytes = function() { 67 return this.req.getBytes(); 68 } 69 70 71 72 /** 73 * Gets the subject name as TLV object 74 * 75 * @return the issuer RDNSequence 76 * @type ASN1 77 */ 78 PKCS10.prototype.getSubject = function() { 79 return this.reqInfo.get(1); 80 } 81 82 83 84 /** 85 * Get the public key 86 * 87 * @type key 88 * @return the public key 89 */ 90 PKCS10.prototype.getPublicKey = function() { 91 var algorithm = this.reqInfo.get(2).get(0).get(0).value; 92 93 var bitString = this.reqInfo.get(2).get(1).value; // subjectPublicKey 94 bitString = PKIXCommon.removeLeadingZeroBytes(bitString); 95 96 var key = new Key(); 97 key.setType(Key.PUBLIC); 98 99 if (algorithm.equals(PKCS10.RSA) || algorithm.equals(PKCS10.RSA_PSS)) { 100 var p = new ASN1(bitString); 101 key.setComponent(Key.MODULUS, PKIXCommon.removeLeadingZeroBytes(p.get(0).value)); 102 key.setComponent(Key.EXPONENT, PKIXCommon.removeLeadingZeroBytes(p.get(1).value)); 103 } else { 104 key.setComponent(Key.ECC_CURVE_OID, this.reqInfo.get(2).get(0).get(1).value); 105 if (bitString.byteAt(0) != 4) { 106 throw new GPError(module.id, GPError.INVALID_MECH, 0, "Only uncompressed keys supported (04)"); 107 } 108 var l = (bitString.length - 1) >> 1; 109 key.setComponent(Key.ECC_QX, bitString.bytes(1, l)); 110 key.setComponent(Key.ECC_QY, bitString.bytes(1 + l, l)); 111 } 112 113 return key; 114 } 115 116 117 118 /** 119 * Get the signature algorithm as Crypto.X constant 120 * 121 * @type Number 122 * @return the signature algorithm 123 */ 124 PKCS10.prototype.getSignatureAlgorithm = function() { 125 var algOID = this.sigAlg.get(0).value; 126 if (this.sigAlg.elements > 1) { 127 var param = this.sigAlg.get(1).getBytes(); 128 } 129 var alg = PKIXCommon.decodeSignatureAlgorithm(algOID, param); 130 131 if (!alg) { 132 throw new GPError(module.id, GPError.INVALID_MECH, alg, "Invalid algorithm"); 133 } 134 return alg; 135 } 136 137 138 139 /** 140 * Get the signature value 141 * 142 * @type ByteString 143 * @return the signature 144 */ 145 PKCS10.prototype.getSignature = function() { 146 var signature = this.sig.value; 147 148 if (signature.byteAt(0) == 0x00) { 149 signature = signature.bytes(1); 150 } 151 return signature; 152 } 153 154 155 156 /** 157 * Verify signature 158 * 159 * @param {Key} pubKey optional public key to use for verification 160 * @type boolean 161 * @return true if signature is valid 162 */ 163 PKCS10.prototype.verify = function(pubKey) { 164 var crypto = new Crypto(); 165 if (!pubKey) { 166 pubKey = this.getPublicKey(); 167 } 168 var alg = this.getSignatureAlgorithm(); 169 var signature = this.getSignature(); 170 171 return crypto.verify(pubKey, alg, this.reqInfo.getBytes(), signature); 172 } 173 174 175 176 PKCS10.prototype.toString = function() { 177 var s = "PKCS#10 Request:"; 178 179 var k = this.getPublicKey(); 180 if (k.getComponent(Key.MODULUS)) { 181 s+= "Type=RSA,"; 182 } else { 183 s+= "Type=EC,"; 184 var curve = ASN1.nameForObjectIdentifier(k.getComponent(Key.ECC_CURVE_OID)); 185 if (curve) { 186 s += "Curve=" + curve + ","; 187 } 188 } 189 s+= "Size=" + k.getSize(); 190 191 var subject = this.getSubject(); 192 if (subject) { 193 var xName = new X509Name(subject) 194 s += "," + xName.toString(); 195 } 196 197 return s; 198 } 199