1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2014 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 /* here we have the possibility to add our own OIDS */
9 
10 #include <openssl/objects.h>
11 #include <QStringList>
12 #include <QMessageBox>
13 #include <QTextEdit>
14 #include <QDebug>
15 #include <QDir>
16 #include "func.h"
17 #include "oid.h"
18 #include "widgets/XcaWarning.h"
19 #include "widgets/MainWindow.h"
20 
21 #ifndef NID_tlsfeature
22 int NID_tlsfeature = NID_undef;
23 #endif
24 
25 int first_additional_oid = 0;
26 
27 NIDlist extkeyuse_nid;
28 NIDlist distname_nid;
29 
30 QMap<QString,const char*> oid_name_clash;
31 QMap<QString,int> oid_lower_map;
32 
addToLowerMap(int nid)33 static void addToLowerMap(int nid)
34 {
35 	QString n = OBJ_nid2sn(nid);
36 	QString l = n.toLower();
37 
38 	if (n != l)
39 		oid_lower_map[l] = nid;
40 	n = OBJ_nid2ln(nid);
41 	l = n.toLower();
42 	if (n != l)
43 		oid_lower_map[l] = nid;
44 }
45 
46 /* reads additional OIDs from a file: oid, sn, ln */
insert_new_oid(const QStringList & sl,QString fname,int line)47 static void insert_new_oid(const QStringList &sl, QString fname, int line)
48 {
49 	bool differs = false;
50 	QByteArray in_use, oid, sn, ln;
51 
52 	oid = sl[0].toLatin1();
53 	sn = sl[1].toLatin1();
54 	ln = sl[2].toLatin1();
55 	if (sl.count() != 3) {
56 		XCA_WARN(QObject::tr("Error reading config file %1 at line %2")
57 			.arg(fname).arg(line));
58 		return;
59 	}
60 
61 	int nid = OBJ_txt2nid(oid.constData());
62 	if (nid != NID_undef) {
63 		/* OID already known by OpenSSL */
64 		if (sn != OBJ_nid2sn(nid)) {
65 			/* ... but with a different ShortName */
66 			qWarning() << "OID: " << oid << "SN differs: " << sn <<
67 				" " << OBJ_nid2sn(nid);
68 			oid_name_clash[sn] = OBJ_nid2sn(nid);
69 			differs = true;
70 		}
71 		if (ln != OBJ_nid2ln(nid)) {
72 			/* ... but with a different LongName */
73 			qWarning() << "OID: " << oid << "LN differs: " << ln <<
74 				" " << OBJ_nid2ln(nid);
75 			oid_name_clash[ln] = OBJ_nid2ln(nid);
76 			differs = true;
77 		}
78 	} else {
79 		/* Check whether ShortName or LongName are already in use
80 		 * for a different OID */
81 		if (OBJ_txt2nid(sn.constData()) != NID_undef)
82 			in_use = sn;
83 		if (OBJ_txt2nid(ln.constData()) != NID_undef)
84 			in_use = ln;
85 	}
86 	ign_openssl_error();
87 	if (differs) {
88 		/* OID exists with different SN or LN. The differing names
89 		 * are added as "alias" in "oid_name_clash" used when loading
90 		 * dn.txt and eku.txt */
91 		XCA_WARN(QObject::tr("The Object '%1' from file %2 line %3 is already known as '%4:%5:%6' and should be removed.")
92 			.arg(sl.join(":")).arg(fname).arg(line)
93 			.arg(OBJ_obj2QString(OBJ_nid2obj(nid), 1))
94 			.arg(OBJ_nid2sn(nid)).arg(OBJ_nid2ln(nid))
95 		);
96 	} else if (!in_use.isEmpty()) {
97 		/* OID does not exist, but SN or LN however do.
98 		 * Do NOT create OID and tell the user about */
99 		nid = OBJ_txt2nid(in_use.constData());
100 		XCA_WARN(QObject::tr("The identifier '%1' for OID %2 from file %3 line %4 is already used for a different OID as '%5:%6:%7' and should be changed to avoid conflicts.")
101 			.arg(in_use.constData())
102 			.arg(oid.constData())
103 			.arg(fname).arg(line)
104 			.arg(OBJ_obj2QString(OBJ_nid2obj(nid), 1))
105 			.arg(OBJ_nid2sn(nid)).arg(OBJ_nid2ln(nid))
106 		);
107 	} else if (nid == NID_undef) {
108 		nid=OBJ_create(oid.constData(), sn.constData(), ln.constData());
109 		qDebug() << "Creating OID:" << fname << line <<
110 						nid << oid << sn << ln;
111 		try {
112 			openssl_error();
113 			addToLowerMap(nid);
114 		} catch (errorEx &e) {
115 			errorEx err(errorEx(e.getString() +
116 				QString("%1:%2 OID: %3")
117 				.arg(fname).arg(line).arg(oid.constData())));
118 			XCA_ERROR(err);
119 		}
120 	}
121 }
122 
readOIDs(QString fname)123 static void readOIDs(QString fname)
124 {
125 	int line = 0;
126 	QFile file(fname);
127 	if (!file.open(QIODevice::ReadOnly))
128                 return;
129 	QTextStream in(&file);
130 	while (!in.atEnd()) {
131 		QString entry = in.readLine().trimmed();
132 		line++;
133 		if (entry.startsWith('#') || entry.isEmpty())
134 			continue;
135 		insert_new_oid(entry.split(QRegExp("\\s*:\\s*")), fname, line);
136 	}
137 }
138 
139 /* reads a list of OIDs/SNs from a file and turns them into a QValueList
140  * of integers, representing the NIDs. Usually to be used by NewX509 for
141  * the list of ExtendedKeyUsage and Distinguished Name
142  */
readNIDlist(const QString & fname)143 static NIDlist readNIDlist(const QString &fname)
144 {
145 	int line = 0, nid;
146 	NIDlist nl;
147 	QFile file(fname);
148 	if (!file.open(QIODevice::ReadOnly))
149                 return nl;
150 
151 	QTextStream in(&file);
152 	while (!in.atEnd()) {
153 		const char *userdefined;
154 		QString entry = in.readLine().trimmed();
155 		line++;
156 		if (entry.startsWith('#') || entry.isEmpty())
157 			continue;
158 		userdefined = oid_name_clash[entry];
159 		if (userdefined)
160 			entry = userdefined;
161 		nid = OBJ_txt2nid(CCHAR(entry));
162 		if (nid == NID_undef)
163 			XCA_WARN(QObject::tr("Unknown object '%1' in file %2 line %3")
164 				.arg(entry).arg(fname).arg(line));
165 		else
166 			nl += nid;
167 	}
168 	openssl_error();
169 	return nl;
170 }
171 
172 /* creates a new nid list from the given filename */
read_nidlist(const QString & name)173 static NIDlist read_nidlist(const QString &name)
174 {
175 	NIDlist nl;
176 
177 	/* first try $HOME/xca/ */
178 	nl = readNIDlist(getUserSettingsDir() + "/" + name);
179 #if !defined(Q_OS_WIN32)
180 #if !defined(Q_OS_MAC)
181 	if (nl.count() == 0){
182 		/* next is /etx/xca/... */
183 		nl = readNIDlist(QString(ETC) + "/" + name);
184 	}
185 #endif
186 #endif
187 	if (nl.count() == 0) {
188 		/* look at /usr/(local/)share/xca/ */
189 		nl = readNIDlist(getPrefix() + "/" + name);
190 	}
191 	return nl;
192 }
193 
initOIDs()194 void initOIDs()
195 {
196 	QString oids("/oids.txt");
197 	QString dir = getPrefix();
198 
199 	first_additional_oid = OBJ_new_nid(0);
200 #ifndef NID_tlsfeature
201 	NID_tlsfeature = OBJ_create("1.3.6.1.5.5.7.1.24", "tlsfeature",
202 							"TLS Feature");
203 #endif
204 	openssl_error();
205 	for (int i=0; i<first_additional_oid;i++)
206 		addToLowerMap(i);
207 	ign_openssl_error();
208 	readOIDs(dir + oids);
209 #if !defined(Q_OS_WIN32)
210 #if !defined(Q_OS_MAC)
211 	readOIDs(QString(ETC) + oids);
212 #endif
213 #endif
214 	readOIDs(getUserSettingsDir() + oids);
215 
216 	extkeyuse_nid = read_nidlist("eku.txt");
217 	distname_nid = read_nidlist("dn.txt");
218 
219 	openssl_error();
220 }
221