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 = "55042C";
 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.commonName)) {
136 		result += "CN=" + this.getRDNAsString(X509Name.commonName);
137 	}
138 
139 	if (this.hasRDN(X509Name.organizationalUnitName)) {
140 		if (result.length > 0)
141 			result += ",";
142 
143 		result += "OU=" + this.getRDNAsString(X509Name.organizationalUnitName);
144 	}
145 
146 	if (this.hasRDN(X509Name.organizationName)) {
147 		if (result.length > 0)
148 			result += ",";
149 
150 		result += "O=" + this.getRDNAsString(X509Name.organizationName);
151 	}
152 
153 	if (this.hasRDN(X509Name.countryName)) {
154 		if (result.length > 0)
155 			result += ",";
156 
157 		result += "C=" + this.getRDNAsString(X509Name.countryName);
158 	}
159 
160 	return result;
161 }