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 }