1 /**
  2  *  ---------
  3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
  4  * |#       #|
  5  * |#       #|  Copyright (c) 1999-2018 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 X509Name - Class to support X500 Names
 25  */
 26 
 27 // 	Name ::= CHOICE {
 28 // 	     RDNSequence }
 29 //
 30 // 	RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
 31 //
 32 // 	RelativeDistinguishedName ::=
 33 // 		SET OF AttributeTypeAndValue
 34 //
 35 // 	AttributeTypeAndValue ::= SEQUENCE {
 36 // 		type     AttributeType,
 37 // 		value    AttributeValue }
 38 //
 39 // 	AttributeType ::= OBJECT IDENTIFIER
 40 //
 41 // 	AttributeValue ::= ANY DEFINED BY AttributeType
 42 
 43 
 44 
 45 X509Name.name = "550429";
 46 X509Name.surname = "550404";
 47 X509Name.givenname = "55042A";
 48 X509Name.initials = "55042B";
 49 X509Name.generationQualifier = "55042C";
 50 X509Name.commonName = "550403";
 51 X509Name.localityName = "550407";
 52 X509Name.stateOrProvinceName = "550408";
 53 X509Name.organizationName = "55040A";
 54 X509Name.organizationalUnitName = "55040B";
 55 X509Name.title = "55040C";
 56 X509Name.dnQualifier = "55042E";
 57 X509Name.countryName = "550406";
 58 X509Name.serialNumber = "550405";
 59 X509Name.emailAddress = "2A864886F70D010901";
 60 
 61 
 62 
 63 function X509Name(subjectDN) {
 64 	this.rdn = new Array();
 65 	this.parseRDNSequence(subjectDN);
 66 }
 67 
 68 exports.X509Name = X509Name;
 69 
 70 
 71 
 72 X509Name.prototype.parseRDNSequence = function(rdnSeq) {
 73 	if (rdnSeq instanceof ASN1) {
 74 		if (!rdnSeq.isconstructed) {
 75 			throw new GPError("X509Name", GPError.INVALID_DATA, 1, "Name must be constructed");
 76 		}
 77 
 78 		if (rdnSeq.tag != ASN1.SEQUENCE) {
 79 			throw new GPError("X509Name", GPError.INVALID_DATA, 1, "RDNSequence must be SEQUENCE");
 80 		}
 81 
 82 		for (var i = 0; i < rdnSeq.elements; i++) {
 83 			var set = rdnSeq.get(i)
 84 			if (set.tag != ASN1.SET) {
 85 				throw new GPError("X509Name", GPError.INVALID_DATA, 1, "RDNSequence must only contain SETs");
 86 			}
 87 			for (var j = 0; j < set.elements; j++) {
 88 				var attr = set.get(j);
 89 				if (attr.tag != ASN1.SEQUENCE) {
 90 					throw new GPError("X509Name", GPError.INVALID_DATA, 1, "AttributeTypeAndValue must be SEQUENCE");
 91 				}
 92 				if (attr.elements != 2) {
 93 					throw new GPError("X509Name", GPError.INVALID_DATA, 1, "AttributeTypeAndValue must have 2 elements");
 94 				}
 95 				var attrType = attr.get(0);
 96 				if (attrType.tag != ASN1.OBJECT_IDENTIFIER) {
 97 					throw new GPError("X509Name", GPError.INVALID_DATA, 1, "AttributeType must be OBJECT IDENTIFIER");
 98 				}
 99 				var oid = attrType.value.toString(HEX);
100 				var attrValue = attr.get(1);
101 				this.rdn[oid] = attrValue;
102 			}
103 		}
104 	} else {
105 		throw new GPError("X509Name", GPError.INVALID_TYPE, 1, "Argument must be of type ASN1");
106 	}
107 }
108 
109 
110 
111 X509Name.prototype.hasRDN = function(oid) {
112 	return this.rdn[oid] != undefined;
113 }
114 
115 
116 
117 X509Name.prototype.getRDNAsString = function(oid) {
118 	var r = this.rdn[oid];
119 	if (r == undefined) {
120 		throw new GPError("X509Name", GPError.INVALID_INDEX,0,"No matching RDN found");
121 	}
122 
123 	if (r.tag == ASN1.UTF8String) {
124 		return r.value.toString(UTF8);
125 	} else {
126 		return r.value.toString(ASCII);
127 	}
128 }
129 
130 
131 
132 X509Name.prototype.toString = function() {
133 	var result = "";
134 
135 	if (this.hasRDN(X509Name.countryName)) {
136 		result += "C=" + this.getRDNAsString(X509Name.countryName);
137 	}
138 
139 	if (this.hasRDN(X509Name.stateOrProvinceName)) {
140 		if (result.length > 0)
141 			result += ",";
142 		result += "ST=" + this.getRDNAsString(X509Name.stateOrProvinceName);
143 	}
144 
145 	if (this.hasRDN(X509Name.organizationName)) {
146 		if (result.length > 0)
147 			result += ",";
148 
149 		result += "O=" + this.getRDNAsString(X509Name.organizationName);
150 	}
151 
152 	if (this.hasRDN(X509Name.organizationalUnitName)) {
153 		if (result.length > 0)
154 			result += ",";
155 
156 		result += "OU=" + this.getRDNAsString(X509Name.organizationalUnitName);
157 	}
158 
159 	if (this.hasRDN(X509Name.localityName)) {
160 		if (result.length > 0)
161 			result += ",";
162 		result += "L=" + this.getRDNAsString(X509Name.localityName);
163 	}
164 
165 	if (this.hasRDN(X509Name.title)) {
166 		if (result.length > 0)
167 			result += ",";
168 		result += "T=" + this.getRDNAsString(X509Name.title);
169 	}
170 
171 	if (this.hasRDN(X509Name.givenname)) {
172 		if (result.length > 0)
173 			result += ",";
174 		result += "G=" + this.getRDNAsString(X509Name.givenname);
175 	}
176 
177 	if (this.hasRDN(X509Name.surname)) {
178 		if (result.length > 0)
179 			result += ",";
180 		result += "S=" + this.getRDNAsString(X509Name.surname);
181 	}
182 
183 	if (this.hasRDN(X509Name.generationQualifier)) {
184 		if (result.length > 0)
185 			result += ",";
186 		result += "generationQualifier=" + this.getRDNAsString(X509Name.generationQualifier);
187 	}
188 
189 	if (this.hasRDN(X509Name.name)) {
190 		if (result.length > 0)
191 			result += ",";
192 		result += "N=" + this.getRDNAsString(X509Name.name);
193 	}
194 
195 	if (this.hasRDN(X509Name.initials)) {
196 		if (result.length > 0)
197 			result += ",";
198 		result += "initials=" + this.getRDNAsString(X509Name.initials);
199 	}
200 
201 	if (this.hasRDN(X509Name.commonName)) {
202 		if (result.length > 0)
203 			result += ",";
204 		result += "CN=" + this.getRDNAsString(X509Name.commonName);
205 	}
206 
207 
208 	if (this.hasRDN(X509Name.serialNumber)) {
209 		if (result.length > 0)
210 			result += ",";
211 		result += "SERIALNUMBER=" + this.getRDNAsString(X509Name.serialNumber);
212 	}
213 
214 	if (this.hasRDN(X509Name.dnQualifier)) {
215 		if (result.length > 0)
216 			result += ",";
217 		result += "DNQ=" + this.getRDNAsString(X509Name.dnQualifier);
218 	}
219 
220 	if (this.hasRDN(X509Name.emailAddress)) {
221 		if (result.length > 0)
222 			result += ",";
223 		result += "E=" + this.getRDNAsString(X509Name.emailAddress);
224 	}
225 
226 	return result;
227 }
228