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 PKIXCommon = require('scsh/x509/PKIXCommon').PKIXCommon; 28 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.EC = new ByteString("id-ecPublicKey", OID); 56 57 58 59 /** 60 * Get the encoded request 61 * 62 * @return the encoded request 63 * @type ByteString 64 */ 65 PKCS10.prototype.getBytes = function() { 66 return this.req.getBytes(); 67 } 68 69 70 71 /** 72 * Gets the subject name as TLV object 73 * 74 * @return the issuer RDNSequence 75 * @type ASN1 76 */ 77 PKCS10.prototype.getSubject = function() { 78 return this.reqInfo.get(1); 79 } 80 81 82 83 /** 84 * Get the public key 85 * 86 * @type key 87 * @return the public key 88 */ 89 PKCS10.prototype.getPublicKey = function() { 90 var algorithm = this.reqInfo.get(2).get(0).get(0).value; 91 92 var bitString = this.reqInfo.get(2).get(1).value; // subjectPublicKey 93 bitString = PKIXCommon.removeLeadingZeroBytes(bitString); 94 95 var key = new Key(); 96 key.setType(Key.PUBLIC); 97 98 if (algorithm.equals(PKCS10.RSA)) { 99 var p = new ASN1(bitString); 100 key.setComponent(Key.MODULUS, PKIXCommon.removeLeadingZeroBytes(p.get(0).value)); 101 key.setComponent(Key.EXPONENT, PKIXCommon.removeLeadingZeroBytes(p.get(1).value)); 102 } else { 103 key.setComponent(Key.ECC_CURVE_OID, this.reqInfo.get(2).get(0).get(1).value); 104 if (bitString.byteAt(0) != 4) { 105 throw new GPError(module.id, GPError.INVALID_MECH, 0, "Only uncompressed keys supported (04)"); 106 } 107 var l = (bitString.length - 1) >> 1; 108 key.setComponent(Key.ECC_QX, bitString.bytes(1, l)); 109 key.setComponent(Key.ECC_QY, bitString.bytes(1 + l, l)); 110 } 111 112 return key; 113 } 114 115 116 117 /** 118 * Get the signature algorithm as Crypto.X constant 119 * 120 * @type Number 121 * @return the signature algorithm 122 */ 123 PKCS10.prototype.getSignatureAlgorithm = function() { 124 var alg = PKIXCommon.decodeSignatureAlgorithm(this.sigAlg.get(0).value); 125 126 if (!alg) { 127 throw new GPError(module.id, GPError.INVALID_MECH, alg, "Invalid algorithm"); 128 } 129 return alg; 130 } 131 132 133 134 /** 135 * Get the signature value 136 * 137 * @type ByteString 138 * @return the signature 139 */ 140 PKCS10.prototype.getSignature = function() { 141 var signature = this.sig.value; 142 143 if (signature.byteAt(0) == 0x00) { 144 signature = signature.bytes(1); 145 } 146 return signature; 147 } 148 149 150 151 /** 152 * Verify signature 153 * 154 * @param {Key} pubKey optional public key to use for verification 155 * @type boolean 156 * @return true if signature is valid 157 */ 158 PKCS10.prototype.verify = function(pubKey) { 159 var crypto = new Crypto(); 160 if (!pubKey) { 161 pubKey = this.getPublicKey(); 162 } 163 var alg = this.getSignatureAlgorithm(); 164 var signature = this.getSignature(); 165 166 return crypto.verify(pubKey, alg, this.reqInfo.getBytes(), signature); 167 } 168 169 170 171 PKCS10.prototype.toString = function() { 172 var s = "PKCS#10 Request:"; 173 174 var k = this.getPublicKey(); 175 if (k.getComponent(Key.MODULUS)) { 176 s+= "Type=RSA,"; 177 } else { 178 s+= "Type=EC,"; 179 var curve = ASN1.nameForObjectIdentifier(k.getComponent(Key.ECC_CURVE_OID)); 180 if (curve) { 181 s += "Curve=" + curve + ","; 182 } 183 } 184 s+= "Size=" + k.getSize(); 185 186 var subject = this.getSubject(); 187 if (subject) { 188 var xName = new X509Name(subject) 189 s += "," + xName.toString(); 190 } 191 192 return s; 193 }