      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