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