1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2011 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 #include "x509v3ext.h"
9 #include "x509name.h"
10 #include "asn1int.h"
11 #include "func.h"
12 #include "exception.h"
13 #include <openssl/x509v3.h>
14 #include <openssl/stack.h>
15 #include <QStringList>
16 #include <QDebug>
17 #include "base.h"
18 #include "BioByteArray.h"
19 
x509v3ext()20 x509v3ext::x509v3ext()
21 {
22 	ext = X509_EXTENSION_new();
23 }
24 
x509v3ext(const X509_EXTENSION * n)25 x509v3ext::x509v3ext(const X509_EXTENSION *n)
26 {
27 	ext = X509_EXTENSION_dup((X509_EXTENSION *)n);
28 }
29 
x509v3ext(const x509v3ext & n)30 x509v3ext::x509v3ext(const x509v3ext &n)
31 {
32 	ASN1_OCTET_STRING *str = n.getData();
33 	ext = X509_EXTENSION_new();
34 	if (str && str->length)
35 		set(n.ext);
36 }
37 
~x509v3ext()38 x509v3ext::~x509v3ext()
39 {
40 	X509_EXTENSION_free(ext);
41 }
42 
set(const X509_EXTENSION * n)43 x509v3ext &x509v3ext::set(const X509_EXTENSION *n)
44 {
45 	if (ext != NULL)
46 		X509_EXTENSION_free(ext);
47 	ext = X509_EXTENSION_dup((X509_EXTENSION *)n);
48 	return *this;
49 }
50 
create(int nid,const QString & et,X509V3_CTX * ctx)51 x509v3ext &x509v3ext::create(int nid, const QString &et, X509V3_CTX *ctx)
52 {
53 	if (ext) {
54 		X509_EXTENSION_free(ext);
55 		ext = NULL;
56 	}
57 	if (!et.isEmpty()) {
58 		QString etext = et;
59 		if (et.contains("DNS:copycn") && ctx && ctx->subject_cert &&
60 		    nid == NID_subject_alt_name)
61 		{
62 			x509name xn(X509_get_subject_name(ctx->subject_cert));
63 			QString cn = xn.getEntryByNid(NID_commonName);
64 			if (!cn.isEmpty())
65 				etext.replace(QString("DNS:copycn"),
66 						QString("DNS:%1").arg(cn));
67 		}
68 		QByteArray ba = etext.toLocal8Bit();
69 		ext = X509V3_EXT_conf_nid(NULL, ctx, nid, ba.data());
70 	}
71 	if (!ext)
72 		ext = X509_EXTENSION_new();
73 	else {
74 		if (ctx && ctx->subject_cert) {
75 			X509_add_ext(ctx->subject_cert, ext, -1);
76 		}
77 	}
78 	return *this;
79 }
80 
create_ia5(int nid,const QString & et,X509V3_CTX * ctx)81 x509v3ext &x509v3ext::create_ia5(int nid, const QString &et, X509V3_CTX *ctx)
82 {
83 	QByteArray ba = et.toLocal8Bit();
84 	for (int i=0; i<ba.size(); i++) {
85 		if (ba[i] & 0x80)
86 			throw errorEx(QObject::tr("String '%1' for '%2' contains invalid characters").arg(et).arg(OBJ_nid2ln(nid)));
87 	}
88 	return create(nid, et, ctx);
89 }
90 
object() const91 const ASN1_OBJECT *x509v3ext::object() const
92 {
93 	ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
94 	try {
95 		openssl_error();
96 	} catch (errorEx e) {
97 		return NULL;
98 	}
99 	return obj;
100 }
101 
nid() const102 int x509v3ext::nid() const
103 {
104 	const ASN1_OBJECT *obj = object();
105 	if (!obj)
106 		return NID_undef;
107 	int nid = OBJ_obj2nid(obj);
108 	if (nid == NID_undef) {
109 		QString o = OBJ_obj2QString(obj, 1);
110 		if (!o.isEmpty())
111 			nid = OBJ_create(CCHAR(o), CCHAR(o), CCHAR(o));
112 	}
113 	return nid;
114 }
115 
d2i() const116 void *x509v3ext::d2i() const
117 {
118 	void *r = X509V3_EXT_d2i(ext);
119 	ign_openssl_error();
120 	return r;
121 }
122 
operator =(const x509v3ext & x)123 x509v3ext &x509v3ext::operator = (const x509v3ext &x)
124 {
125 	set(x.ext);
126 	return *this;
127 }
128 
getObject() const129 QString x509v3ext::getObject() const
130 {
131 	const ASN1_OBJECT *obj = object();
132 	return obj ? OBJ_obj2QString(obj) : QString("<ERROR>");
133 }
134 
getCritical() const135 int x509v3ext::getCritical() const
136 {
137 	return X509_EXTENSION_get_critical(ext);
138 }
139 
getData() const140 ASN1_OCTET_STRING *x509v3ext::getData() const
141 {
142 	return X509_EXTENSION_get_data(ext);
143 }
144 
getValue() const145 QString x509v3ext::getValue() const
146 {
147 	BioByteArray bba;
148 	int ret = X509V3_EXT_print(bba, ext, X509V3_EXT_DEFAULT, 0);
149 	if (ign_openssl_error() || !ret)
150 		ret = ASN1_STRING_print(bba, (ASN1_STRING *)getData());
151 	if (ign_openssl_error() || !ret)
152 		return QString();
153 	return bba.qstring().trimmed();
154 }
155 
getHtmlValue() const156 QString x509v3ext::getHtmlValue() const
157 {
158 	QString text = getValue();
159 	text.replace(QRegExp("&"), "&amp;");
160 	text.replace(QRegExp("<"), "&lt;");
161 	text.replace(QRegExp(">"), "&gt;");
162 	text.replace(QRegExp("\n"), "<br>\n");
163 	return text;
164 }
165 
getConsoleValue(const QString & indent) const166 QString x509v3ext::getConsoleValue(const QString &indent) const
167 {
168 	QString text = getValue();
169 	text.replace(QRegExp("\n"), QString("\n") + indent);
170 	return text;
171 }
172 
vlist2Section(QStringList vlist,QString tag,QString * sect)173 static QString vlist2Section(QStringList vlist, QString tag, QString *sect)
174 {
175 	/* Check for commas in the text */
176 	if (!vlist.join("").contains(","))
177 		return vlist.join(", ");
178 
179 	*sect += QString("\n[%1_sect]\n").arg(tag);
180 
181 	for (int i=0; i<vlist.count(); i++) {
182 		QString s = vlist[i];
183 		int eq = s.indexOf(":");
184 		*sect += QString("%1.%2=%3\n").arg(s.left(eq)).
185 			arg(i).arg(s.mid(eq+1));
186 	}
187 	return QString("@%1_sect\n").arg(tag);
188 }
189 
obj2SnOid(const ASN1_OBJECT * a)190 static QString obj2SnOid(const ASN1_OBJECT *a)
191 {
192 	QString obj;
193 	int nid = OBJ_obj2nid(a);
194 
195 	if (nid == NID_undef)
196 		obj = OBJ_obj2QString(a);
197 	else
198 		obj = OBJ_nid2sn(nid);
199 
200 	return obj;
201 }
202 
asn1Type2Name(int type)203 static const char *asn1Type2Name(int type)
204 {
205 #define ASN1_GEN_STR(x,y) { x,y }
206 	struct {
207 	        const char *strnam;
208 		int tag;
209 	} tags[] = {
210 		ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN),
211 		ASN1_GEN_STR("NULL", V_ASN1_NULL),
212 		ASN1_GEN_STR("INT", V_ASN1_INTEGER),
213 		ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED),
214 		ASN1_GEN_STR("OID", V_ASN1_OBJECT),
215 		ASN1_GEN_STR("UTC", V_ASN1_UTCTIME),
216 		ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME),
217 		ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING),
218 		ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING),
219 		ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING),
220 		ASN1_GEN_STR("IA5", V_ASN1_IA5STRING),
221 		ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING),
222 		ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING),
223 		ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING),
224 		ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING),
225 		ASN1_GEN_STR("T61", V_ASN1_T61STRING),
226 		ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING),
227 		ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING),
228 	};
229 	for (unsigned i=0; i< ARRAY_SIZE(tags); i++) {
230 		if (tags[i].tag == type)
231 			return tags[i].strnam;
232 	}
233 	return "UNKNOWN";
234 }
235 
asn1TypePrintable(int type)236 static bool asn1TypePrintable(int type)
237 {
238 	switch (type) {
239 	case V_ASN1_IA5STRING:
240 	case V_ASN1_UTF8STRING:
241 	case V_ASN1_BMPSTRING:
242 	case V_ASN1_VISIBLESTRING:
243 	case V_ASN1_PRINTABLESTRING:
244 	case V_ASN1_T61STRING:
245 	case V_ASN1_GENERALSTRING:
246 		return true;
247 	}
248 	return false;
249 }
250 
ipv6_from_binary(const unsigned char * p)251 static QString ipv6_from_binary(const unsigned char *p)
252 {
253 	QString ip;
254 	int i, skip =0, skiplen = 0, skippos =0;
255 
256 	/* find largest gap */
257 	for (i = 0; i < 17; i += 2) {
258 		if (i==16 || (p[i] | p[i +1])) {
259 			if (skiplen < skip) {
260 				skiplen = skip;
261 				skippos = i - skip;
262 			}
263 			skip = 0;
264 		} else {
265 			skip += 2;
266 		}
267 	}
268 	for (i = 0, skip = 0; i < 16; i += 2) {
269 		int x = p[i] << 8 | p[i+1];
270 		skip += skippos == i;
271 		switch (!x*4 + skip) {
272 		case 5: // skip first 0
273 			skip = 2;
274 			ip += ":";
275 		case 6: // skip next 0
276 			break;
277 		default: // no reduction
278 			skip = 0;
279 			ip += QString("%1%2").arg(i? ":" : "").arg(x,0,16);
280 		}
281 	}
282 	if (skip == 2)
283 		ip += ":";
284 	return ip;
285 }
286 
287 static bool
genName2conf(GENERAL_NAME * gen,QString tag,QString * single,QString * sect)288 genName2conf(GENERAL_NAME *gen, QString tag, QString *single, QString *sect)
289 {
290 	unsigned char *p;
291 	QString ret;
292 
293 	switch (gen->type) {
294 	case GEN_EMAIL: ret = "email:%1"; break;
295 	case GEN_DNS:   ret = "DNS:%1"; break;
296 	case GEN_URI:   ret = "URI:%1"; break;
297 
298 	case GEN_DIRNAME: {
299 		tag += "_dirname";
300 		x509name xn(gen->d.dirn);
301 		*sect += QString("\n[%1]\n"). arg(tag);
302 		*sect += xn.taggedValues();
303 		*single = QString("dirName:") + tag;
304 		return true;
305 	}
306 	case GEN_IPADD:
307 		p = gen->d.ip->data;
308 		if (gen->d.ip->length == 4) {
309 			*single = QString("IP:%1.%2.%3.%4").
310 				arg(p[0]).arg(p[1]).arg(p[2]).arg(p[3]);
311 			return true;
312 		} else if(gen->d.ip->length == 8) {
313 			 *single = QString("IP:%1.%2.%3.%4/%5.%6.%7.%8").
314                                 arg(p[0]).arg(p[1]).arg(p[2]).arg(p[3]).
315                                 arg(p[4]).arg(p[5]).arg(p[6]).arg(p[7]);
316                         return true;
317 		} else if(gen->d.ip->length == 16) {
318 			*single = "IP:" + ipv6_from_binary(gen->d.ip->data);
319 			return true;
320 		} else if(gen->d.ip->length == 32) {
321 			*single = "IP:" + ipv6_from_binary(gen->d.ip->data) +
322 				"/" + ipv6_from_binary(gen->d.ip->data +16);
323 			return true;
324 		}
325 		return false;
326 
327 	case GEN_RID:
328 		*single = QString("RID:%1").
329 				arg(obj2SnOid(gen->d.rid));
330 		return true;
331 	case GEN_OTHERNAME: {
332 		int type = gen->d.otherName->value->type;
333 		ASN1_STRING *a;
334 		a = gen->d.otherName->value->value.asn1_string;
335 		if (asn1TypePrintable(type)) {
336 			*single = QString("otherName:%1;%2:%3").
337 			arg(obj2SnOid(gen->d.otherName->type_id)).
338 			arg(asn1Type2Name(type)).
339 			arg(asn1ToQString(a, true));
340 		} else {
341 			*single = QString("otherName:%1;FORMAT:HEX,%2").
342 			arg(obj2SnOid(gen->d.otherName->type_id)).
343 			arg(asn1Type2Name(type));
344 			for (int i=0; i<a->length; i++) {
345 				*single += QString(":%1").
346 				arg((int)(a->data[i]), 2, 16, QChar('0'));
347 			}
348 		}
349 		return true;
350 	}
351 	default:
352 		return false;
353 	}
354 	if (!ret.isEmpty())
355 		*single = ret.arg(asn1ToQString(gen->d.ia5, true));
356 	return true;
357 }
358 
genNameStack2conf(STACK_OF (GENERAL_NAME)* gens,QString tag,QString * single,QString * sect)359 static bool genNameStack2conf(STACK_OF(GENERAL_NAME) *gens, QString tag,
360 				QString *single, QString *sect)
361 {
362 	int i;
363 	QStringList sl;
364 	for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
365 		QString one;
366 		if (!genName2conf(sk_GENERAL_NAME_value(gens, i),
367 			QString("%1_%2").arg(tag).arg(i), &one, sect))
368 		{
369 			return false;
370 		}
371 		sl << one;
372 	}
373 	*single = vlist2Section(sl, tag, sect);
374 	return true;
375 }
376 
parse_critical() const377 QString x509v3ext::parse_critical() const
378 {
379 	return QString(getCritical() ? "critical," : "");
380 }
381 
382 #define TEXTS (\
383 	B_ASN1_TIME | B_ASN1_DIRECTORYSTRING | B_ASN1_DISPLAYTEXT | \
384 	B_ASN1_NUMERICSTRING | B_ASN1_T61STRING | B_ASN1_UNIVERSALSTRING)
385 
parse_ia5(QString * single,QString * adv) const386 bool x509v3ext::parse_ia5(QString *single, QString *adv) const
387 {
388 	ASN1_STRING *str = (ASN1_STRING *)d2i();
389 	QString ret;
390 
391 	if (!str) {
392 		const unsigned char *p = getData()->data;
393 		str = d2i_ASN1_OCTET_STRING(NULL, &p, getData()->length);
394 		if (ign_openssl_error() || !str)
395 			return false;
396 		ret = QString("<ERROR: NOT IA5 but %1>%2").
397 			arg(asn1Type2Name(str->type)).
398 			arg(QString(asn1ToQString(str)));
399 	} else {
400 		ret = QString(asn1ToQString(str));
401 	}
402 	if (single)
403 		*single = ret;
404 	else if (adv)
405 		*adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
406 
407 	ASN1_STRING_free(str);
408 	return true;
409 }
410 
parse_generalName(QString * single,QString * adv) const411 bool x509v3ext::parse_generalName(QString *single, QString *adv) const
412 {
413 	bool retval = true;
414 	QString sect, ret;
415 	STACK_OF(GENERAL_NAME) *gens = (STACK_OF(GENERAL_NAME) *)d2i();
416 
417 	if (!gens)
418 		return false;
419 
420 	QString tag = OBJ_nid2sn(nid());
421 
422 	if (!genNameStack2conf(gens, tag, &ret, &sect))
423 		retval = false;
424 	else if (sect.isEmpty() && single) {
425 		*single = parse_critical() + ret;
426 	} else if (adv) {
427 		*adv = QString("%1=%2\n").arg(tag).
428 			arg(parse_critical() +ret) + *adv + sect;
429 	}
430 	sk_GENERAL_NAME_free(gens);
431 	return retval;
432 }
433 
parse_eku(QString * single,QString * adv) const434 bool x509v3ext::parse_eku(QString *single, QString *adv) const
435 {
436 	EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE *)d2i();
437 	QStringList sl;
438 	int i;
439 
440 	if (!eku)
441 		return false;
442 
443 	for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
444 		sl << QString(OBJ_obj2sn(sk_ASN1_OBJECT_value(eku, i)));
445 	}
446 	QString r = parse_critical() + sl.join(", ");
447 	if (single)
448 		*single = r;
449 	else if (adv)
450 		*adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(r) + *adv;
451 
452 	EXTENDED_KEY_USAGE_free(eku);
453 	return true;
454 }
455 
parse_ainfo(QString * single,QString * adv) const456 bool x509v3ext::parse_ainfo(QString *single, QString *adv) const
457 {
458 	bool retval = true;
459 	QString sect, ret;
460         QString tag = OBJ_nid2sn(nid());
461 	QStringList sl;
462 	int i;
463 
464 	AUTHORITY_INFO_ACCESS *ainfo = (AUTHORITY_INFO_ACCESS *)d2i();
465 
466 	if (!ainfo)
467 		return false;
468 
469 	for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) {
470 		QString one;
471 		ACCESS_DESCRIPTION *desc = sk_ACCESS_DESCRIPTION_value(ainfo, i);
472 		if (!genName2conf(desc->location,
473 			QString("%1_%2").arg(tag).arg(i), &one, &sect))
474 		{
475 			retval = false;
476 			break;
477 		}
478 		sl << QString("%1;%2").arg(OBJ_obj2sn(desc->method)).arg(one);
479 	}
480 	if (retval) {
481 		ret = vlist2Section(sl, tag, &sect);
482 		if (sect.isEmpty() && sk_ACCESS_DESCRIPTION_num(ainfo) == 1 && single) {
483 			*single = parse_critical() + ret;
484 		} else if (adv) {
485 			*adv = QString("%1=%2\n").arg(tag).
486 				arg(parse_critical() + ret) + *adv + sect;
487 		}
488 	}
489 	AUTHORITY_INFO_ACCESS_free(ainfo);
490 	return retval;
491 }
492 
493 static const BIT_STRING_BITNAME reason_flags[] = {
494 {0, "", "unused"},
495 {1, "", "keyCompromise"},
496 {2, "", "CACompromise"},
497 {3, "", "affiliationChanged"},
498 {4, "", "superseded"},
499 {5, "", "cessationOfOperation"},
500 {6, "", "certificateHold"},
501 {7, "", "privilegeWithdrawn"},
502 {8, "", "AACompromise"},
503 {-1, NULL, NULL}
504 };
505 
parse_bits(const BIT_STRING_BITNAME * flags,ASN1_BIT_STRING * str)506 static QString parse_bits(const BIT_STRING_BITNAME *flags,
507 				ASN1_BIT_STRING *str)
508 {
509 	const BIT_STRING_BITNAME *pbn;
510 	QStringList r;
511 	for (pbn = flags; pbn->sname; pbn++) {
512 		if (ASN1_BIT_STRING_get_bit(str, pbn->bitnum))
513 			r << QString(pbn->sname);
514 	}
515 	return r.join(", ");
516 }
517 
parse_Crldp(QString * single,QString * adv) const518 bool x509v3ext::parse_Crldp(QString *single, QString *adv) const
519 {
520 	QString othersect;
521 	QStringList crldps;
522 	const char *sn = OBJ_nid2sn(nid());
523 
524 	STACK_OF(DIST_POINT) *crld = (STACK_OF(DIST_POINT)*)d2i();
525 
526 	if (!crld)
527 		return false;
528 
529 	if (sk_DIST_POINT_num(crld) == 1 && single) {
530 		DIST_POINT *point = sk_DIST_POINT_value(crld, 0);
531 		if (point->distpoint && !point->reasons && !point->CRLissuer &&
532 		    !point->distpoint->type)
533 		{
534 			QString sect, ret;
535 			if (!genNameStack2conf(point->distpoint->name.fullname,
536 						"", &ret, &sect))
537 				goto could_not_parse;
538 
539 			if (sect.isEmpty()) {
540 				if (single)
541 					*single = parse_critical() +ret;
542 				else if (adv)
543 					*adv = QString("%1=%2\n").arg(sn).
544 					       arg(parse_critical() +ret) +*adv;
545 				return true;
546 			}
547 		}
548 	}
549 	for(int i = 0; i < sk_DIST_POINT_num(crld); i++) {
550 		DIST_POINT *point = sk_DIST_POINT_value(crld, i);
551 		QString tag = QString("crlDistributionPoint%1_sect").arg(i);
552 		QString crldpsect = QString("\n[%1]\n").arg(tag);
553 		if (point->distpoint) {
554 			if (!point->distpoint->type) {
555 				QString ret;
556 				if (!genNameStack2conf(point->distpoint->name.fullname,
557 						tag + "_fullname", &ret, &othersect))
558 					goto could_not_parse;
559 
560 				crldpsect += "fullname=" + ret +"\n";
561 			} else {
562 				QString mysect = tag + "_relativename";
563 				x509name xn(point->distpoint->name.relativename);
564 				crldpsect += "relativename=" + mysect + "\n";
565 				othersect += QString("\n[%1]\n").arg(mysect) +
566 						xn.taggedValues();
567 			}
568 		}
569 		if (point->reasons) {
570 			crldpsect += QString("reasons=%1\n").
571 				arg(parse_bits(reason_flags, point->reasons));
572 		}
573 		if (point->CRLissuer) {
574 			QString ret;
575 			if (genNameStack2conf(point->CRLissuer,
576 					tag +"_crlissuer", &ret, &othersect))
577 				goto could_not_parse;
578 			crldpsect += "CRLissuer=" + ret + "\n";
579 		}
580 		crldps << tag;
581 		othersect = crldpsect + othersect;
582 	}
583 	sk_DIST_POINT_free(crld);
584 	if (crldps.size() == 0)
585 		return true;
586 	if (adv) {
587 		*adv = QString("%1=%2\n").arg(sn).
588 			arg(parse_critical() + crldps.join(", ")) +
589 			*adv + othersect;
590 
591 #if OPENSSL_VERSION_NUMBER < 0x10000000L
592 		*adv = QString( "\n"
593 			"# This syntax only works for openssl >= 1.0.0\n"
594 			"# But this is %1\n"
595 			"# ").arg(OPENSSL_VERSION_TEXT) + *adv;
596 #endif
597 	}
598 	return true;
599 
600 could_not_parse:
601 	sk_DIST_POINT_free(crld);
602 	return false;
603 }
604 
gen_cpol_notice(QString tag,USERNOTICE * notice,QString * adv)605 static void gen_cpol_notice(QString tag, USERNOTICE *notice, QString *adv)
606 {
607 	*adv += QString("\n[%1]\n").arg(tag);
608 	if (notice->exptext) {
609 		*adv += QString("explicitText=%1\n").
610 				arg(asn1ToQString(notice->exptext, true));
611 	}
612 	if (notice->noticeref) {
613 		NOTICEREF *ref = notice->noticeref;
614 		QStringList sl;
615 		int i;
616 		*adv += QString("organization=%1\n").
617                                 arg(asn1ToQString(ref->organization, true));
618 		for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
619 			a1int num(sk_ASN1_INTEGER_value(ref->noticenos, i));
620 			sl << num.toDec();
621                 }
622 		if (sl.size())
623 			*adv += QString("noticeNumbers=%1\n").
624 					arg(sl.join(", "));
625 	}
626 }
627 
gen_cpol_qual_sect(QString tag,POLICYINFO * pinfo,QString * adv)628 static bool gen_cpol_qual_sect(QString tag, POLICYINFO *pinfo, QString *adv)
629 {
630 	QString polsect = QString("\n[%1]\n").arg(tag);
631 	QString noticetag, _adv;
632 	STACK_OF(POLICYQUALINFO) *quals = pinfo->qualifiers;
633 	int i;
634 
635 	if (!quals)
636 		return false;
637 
638 	if (!adv)
639 		adv = &_adv;
640 
641 	polsect += QString("policyIdentifier=%1\n").
642 			arg(obj2SnOid(pinfo->policyid));
643 
644 	for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
645 		POLICYQUALINFO *qualinfo = sk_POLICYQUALINFO_value(quals, i);
646                 switch (OBJ_obj2nid(qualinfo->pqualid)) {
647 		case NID_id_qt_cps:
648 			polsect += QString("CPS.%1=%2\n").arg(i).
649 					arg(asn1ToQString(qualinfo->d.cpsuri, true));
650 			break;
651 		case NID_id_qt_unotice:
652 			noticetag = QString("%1_notice%2_sect").arg(tag).arg(i);
653 			polsect += QString("userNotice.%1=@%2\n").arg(i).
654 					arg(noticetag);
655 			gen_cpol_notice(noticetag, qualinfo->d.usernotice, adv);
656 			break;
657 		default:
658 			return false;
659 		}
660 	}
661 	*adv = polsect + *adv;
662 	return true;
663 }
664 
665 
parse_certpol(QString *,QString * adv) const666 bool x509v3ext::parse_certpol(QString *, QString *adv) const
667 {
668 	bool retval = true;
669 	QStringList pols;
670 	QString myadv;
671 	int i;
672 	STACK_OF(POLICYINFO) *pol = (STACK_OF(POLICYINFO) *)d2i();
673 
674 	if (!pol)
675 		return false;
676 
677 	for (i = 0; i < sk_POLICYINFO_num(pol); i++) {
678 		POLICYINFO *pinfo = sk_POLICYINFO_value(pol, i);
679 		if (!pinfo->qualifiers) {
680 			pols << obj2SnOid(pinfo->policyid);
681 			continue;
682 		}
683 		QString tag = QString("certpol%1_sect").arg(i);
684 		pols << QString("@") + tag;
685 		if (!gen_cpol_qual_sect(tag, pinfo, &myadv)) {
686 			retval = false;
687 			break;
688 		}
689 	}
690 	if (retval && adv)
691 		*adv = QString("certificatePolicies=%1ia5org,%2\n").
692 		arg(parse_critical()).arg(pols.join(", ")) + *adv + myadv;
693 	sk_POLICYINFO_free(pol);
694 	return retval;
695 }
696 
parse_bc(QString * single,QString * adv) const697 bool x509v3ext::parse_bc(QString *single, QString *adv) const
698 {
699 	BASIC_CONSTRAINTS *bc = (BASIC_CONSTRAINTS *)d2i();
700 
701 	if (!bc)
702 		return false;
703 
704 	QString ret = a1int(bc->pathlen).toDec();
705 	if (!ret.isEmpty())
706 		ret = ",pathlen:" + ret;
707 	ret = parse_critical() + (bc->ca ? "CA:TRUE" : "CA:FALSE") + ret;
708 	if (single)
709 		*single = ret;
710 	else if (adv)
711 		*adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
712 	BASIC_CONSTRAINTS_free(bc);
713 	return true;
714 }
715 
716 static const BIT_STRING_BITNAME key_usage_type_table[] = {
717 {0, "Digital Signature", "digitalSignature"},
718 {1, "Non Repudiation", "nonRepudiation"},
719 {2, "Key Encipherment", "keyEncipherment"},
720 {3, "Data Encipherment", "dataEncipherment"},
721 {4, "Key Agreement", "keyAgreement"},
722 {5, "Certificate Sign", "keyCertSign"},
723 {6, "CRL Sign", "cRLSign"},
724 {7, "Encipher Only", "encipherOnly"},
725 {8, "Decipher Only", "decipherOnly"},
726 {-1, NULL, NULL}
727 };
728 
729 static const BIT_STRING_BITNAME ns_cert_type_table[] = {
730 {0, "SSL Client", "client"},
731 {1, "SSL Server", "server"},
732 {2, "S/MIME", "email"},
733 {3, "Object Signing", "objsign"},
734 {4, "Unused", "reserved"},
735 {5, "SSL CA", "sslCA"},
736 {6, "S/MIME CA", "emailCA"},
737 {7, "Object Signing CA", "objCA"},
738 {-1, NULL, NULL}
739 };
740 
parse_bitstring(QString * single,QString * adv) const741 bool x509v3ext::parse_bitstring(QString *single, QString *adv) const
742 {
743 	ASN1_BIT_STRING *bs;
744 	const BIT_STRING_BITNAME *bnames;
745 	int n = nid();
746 
747 	switch (n) {
748 	case NID_key_usage: bnames = key_usage_type_table; break;
749 	case NID_netscape_cert_type: bnames = ns_cert_type_table; break;
750 	default: return false;
751 	}
752 	bs = (ASN1_BIT_STRING *)d2i();
753 
754 	if (!bs)
755 		return false;
756 
757 	QString ret = parse_critical() + parse_bits(bnames, bs);
758 	if (single)
759 		*single = ret;
760 	else if (adv)
761 		*adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
762 	ASN1_BIT_STRING_free(bs);
763         return true;
764 }
765 
parse_sKeyId(QString *,QString * adv) const766 bool x509v3ext::parse_sKeyId(QString *, QString *adv) const
767 {
768 	if (adv)
769 		*adv = QString("%1=hash\n").arg(OBJ_nid2sn(nid())) + *adv;
770 	return true;
771 }
772 
parse_aKeyId(QString *,QString * adv) const773 bool x509v3ext::parse_aKeyId(QString *, QString *adv) const
774 {
775 	QStringList ret;
776 	AUTHORITY_KEYID *akeyid = (AUTHORITY_KEYID *)d2i();
777 
778 	if (!akeyid)
779 		return false;
780 
781 	if (akeyid->keyid)
782 		ret << "keyid";
783 	if (akeyid->issuer)
784 		ret << "issuer:always";
785 	if (adv)
786 		*adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).
787 			arg(ret.join(", ")) + *adv;
788 	AUTHORITY_KEYID_free(akeyid);
789 	return true;
790 }
791 
parse_generic(QString *,QString * adv) const792 bool x509v3ext::parse_generic(QString *, QString *adv) const
793 {
794 	const ASN1_OBJECT *o = object();
795 	QString der, obj = o ? obj2SnOid(o) : QString("<ERROR>");
796 	ASN1_OCTET_STRING *v = getData();
797 
798 	for (int i=0; i<v->length; i++)
799 		der += QString(":%1").arg((int)(v->data[i]), 2, 16, QChar('0'));
800 
801 	if (adv)
802 		*adv = QString("%1=%2DER%3\n").arg(obj).
803 				arg(parse_critical()).arg(der) +
804 			*adv;
805 	return true;
806 }
807 
parse_inhibitAnyPolicy(QString *,QString * adv) const808 bool x509v3ext::parse_inhibitAnyPolicy(QString *, QString *adv) const
809 {
810 	ASN1_INTEGER *a = (ASN1_INTEGER *)d2i();
811 
812 	if (!a)
813 		return false;
814 
815 	a1int val(a);
816 	if (adv) {
817 		*adv = QString("%1=%2%3\n").arg(OBJ_nid2sn(nid())).
818 			arg(parse_critical()).arg(val.toDec()) + *adv;
819 	}
820 	ASN1_INTEGER_free(a);
821 	return true;
822 }
823 
parse_policyConstraints(QString *,QString * adv) const824 bool x509v3ext::parse_policyConstraints(QString *, QString *adv) const
825 {
826 	QStringList v;
827 	a1int a1null(0L), a;
828 	POLICY_CONSTRAINTS *pol = (POLICY_CONSTRAINTS *)d2i();
829 
830 	if (!pol)
831 		return false;
832 
833 	a = a1int(pol->requireExplicitPolicy);
834 	if (a != a1null)
835 		v << QString("requireExplicitPolicy:%1").arg(a.toDec());
836 
837 	a = a1int(pol->inhibitPolicyMapping);
838 	if (a != a1null)
839 		v << QString("inhibitPolicyMapping:%1").arg(a.toDec());
840 
841 	if (adv)
842 		*adv = QString("%1=%2%3\n").arg(OBJ_nid2sn(nid())).
843 			arg(parse_critical()).arg(v.join(", ")) + *adv;
844 	POLICY_CONSTRAINTS_free(pol);
845 	return true;
846 
847 }
848 
parse_policyMappings(QString *,QString * adv) const849 bool x509v3ext::parse_policyMappings(QString *, QString *adv) const
850 {
851 	bool retval = true;
852 	QStringList polMaps;
853 	QString myadv;
854 	POLICY_MAPPINGS *pmaps = (POLICY_MAPPINGS *)d2i();
855 
856 	if (!pmaps)
857 		return false;
858 
859 	for (int i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) {
860 		POLICY_MAPPING *pmap = sk_POLICY_MAPPING_value(pmaps, i);
861 		polMaps << QString("%1 = %2").
862 			arg(obj2SnOid(pmap->issuerDomainPolicy)).
863 			arg(obj2SnOid(pmap->subjectDomainPolicy));
864 	}
865 	if (polMaps.size() > 0 && adv) {
866 		*adv = QString("policyMappings=%1@policyMappings_sect\n").
867 		arg(parse_critical()) + *adv +
868 		QString("[policyMappings_sect]\n") + polMaps.join("\n");
869 	}
870 	sk_POLICY_MAPPING_free(pmaps);
871 	return retval;
872 }
873 
nameConstraint(STACK_OF (GENERAL_SUBTREE)* trees,QString prefix,QString tag,QString * single,QString * sect)874 static bool nameConstraint(STACK_OF(GENERAL_SUBTREE) *trees,
875 		QString prefix, QString tag, QString *single, QString *sect)
876 {
877 	QStringList sl;
878 	for (int i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
879 		QString one;
880 		GENERAL_SUBTREE *tree = sk_GENERAL_SUBTREE_value(trees, i);
881 		if (!genName2conf(tree->base,
882 			QString("%1_%2").arg(tag).arg(i), &one, sect))
883 		{
884 			return false;
885 		}
886 		qDebug("%s: %d '%s'\n", __func__, i, CCHAR(one));
887 		sl << prefix + ";" + one;
888 	}
889 	*single = vlist2Section(sl, tag+prefix, sect);
890 	qDebug("Single: '%s'\n", CCHAR(*single));
891 	return true;
892 }
893 
parse_nameConstraints(QString *,QString * adv) const894 bool x509v3ext::parse_nameConstraints(QString *, QString *adv) const
895 {
896 	bool retval = true;
897 	QString sect, ret;
898 	QStringList permEx;
899 	QString tag = OBJ_nid2sn(nid());
900 	NAME_CONSTRAINTS *cons = (NAME_CONSTRAINTS *)d2i();
901 
902 	if (!cons)
903 		return false;
904 
905 	if (!nameConstraint(cons->permittedSubtrees, "permitted",
906 				tag, &ret, &sect))
907 		retval = false;
908 	if (ret.size() > 0)
909 		permEx << ret;
910 	if (!nameConstraint(cons->excludedSubtrees, "excluded",
911 				tag, &ret, &sect))
912 		retval = false;
913 	if (ret.size() > 0)
914 		permEx << ret;
915 
916 	if (adv && retval &&permEx.size() > 0) {
917 		ret = permEx.join(", ");
918 		qDebug("%s %d '%s'\n", __func__, retval, CCHAR(ret));
919 		*adv = QString("%1=%2\n").arg(tag).
920 			arg(parse_critical() +ret) + *adv + sect;
921 	}
922 	NAME_CONSTRAINTS_free(cons);
923 	return retval;
924 }
925 
genConf(QString * single,QString * adv) const926 bool x509v3ext::genConf(QString *single, QString *adv) const
927 {
928 	int n = nid();
929 	switch (n) {
930 	case NID_crl_distribution_points:
931 		return parse_Crldp(single, adv);
932 	case NID_subject_alt_name:
933 	case NID_issuer_alt_name:
934 		return parse_generalName(single, adv);
935 	case NID_info_access:
936 		return parse_ainfo(single, adv);
937 	case NID_ext_key_usage:
938 		return parse_eku(single, adv);
939 	case NID_certificate_policies:
940 		return parse_certpol(single, adv);
941 	case NID_netscape_comment:
942 	case NID_netscape_base_url:
943 	case NID_netscape_revocation_url:
944 	case NID_netscape_ca_revocation_url:
945 	case NID_netscape_renewal_url:
946 	case NID_netscape_ca_policy_url:
947 	case NID_netscape_ssl_server_name:
948 		return parse_ia5(single, adv);
949 	case NID_basic_constraints:
950 		return parse_bc(single, adv);
951 	case NID_key_usage:
952 	case NID_netscape_cert_type:
953 		return parse_bitstring(single, adv);
954 	case NID_subject_key_identifier:
955 		return parse_sKeyId(single, adv);
956 	case NID_authority_key_identifier:
957 		return parse_aKeyId(single, adv);
958 	case NID_inhibit_any_policy:
959 		return parse_inhibitAnyPolicy(single, adv);
960 	case NID_policy_constraints:
961 		return parse_policyConstraints(single, adv);
962 	case NID_policy_mappings:
963 		return parse_policyMappings(single, adv);
964 	case NID_name_constraints:
965 		return parse_nameConstraints(single, adv);
966 	case NID_id_pkix_OCSP_noCheck:
967 		if (adv)
968 			*adv = "noCheck = ignored\n" + *adv;
969 		return true;
970 	default:
971 		return parse_generic(single, adv);
972 	}
973 	return false;
974 }
975 
getHtml() const976 QString x509v3ext::getHtml() const
977 {
978 	QString html;
979 	html = "<b><u>" + getObject();
980 	if (getCritical() != 0)
981 		html += " <font color=\"red\">critical</font>";
982 	html += ":</u></b><br><tt>" + getHtmlValue() + "</tt>";
983 	return html;
984 }
985 
getConsole(const QString & indent) const986 QString x509v3ext::getConsole(const QString &indent) const
987 {
988 	QString text, twoind = indent + indent;
989 	text = indent + COL_BOLD COL_UNDER + getObject();
990 	if (getCritical() != 0)
991 		text += " " COL_RED COL_UNDER "[critical]";
992 	text += COL_RESET "\n" + twoind + getConsoleValue(twoind);
993 	return text;
994 }
995 
get() const996 X509_EXTENSION *x509v3ext::get() const
997 {
998 	return X509_EXTENSION_dup(ext);
999 }
1000 
isValid() const1001 bool x509v3ext::isValid() const
1002 {
1003 	return ext && getData() && getData()->length > 0 &&
1004 		OBJ_obj2nid(X509_EXTENSION_get_object(ext)) != NID_undef;
1005 }
1006 
1007 /*************************************************************/
1008 
genConf(int nid,QString * single,QString * adv)1009 bool extList::genConf(int nid, QString *single, QString *adv)
1010 {
1011 	int i = idxByNid(nid);
1012 	if (i != -1) {
1013 		if (at(i).genConf(single, adv))
1014 			removeAt(i);
1015 		ign_openssl_error();
1016 		return true;
1017 	}
1018 	return false;
1019 }
1020 
genGenericConf(QString * adv)1021 void extList::genGenericConf(QString *adv)
1022 {
1023 	for (int i=0; i< size();) {
1024 		if (at(i).genConf(NULL, adv) || at(i).parse_generic(NULL, adv))
1025 			removeAt(i);
1026 		else
1027 			i++;
1028 		ign_openssl_error();
1029 	}
1030 }
1031 
setStack(const STACK_OF (X509_EXTENSION)* st,int start)1032 void extList::setStack(const STACK_OF(X509_EXTENSION) *st, int start)
1033 {
1034 	clear();
1035 	int cnt = sk_X509_EXTENSION_num(st);
1036 	x509v3ext e;
1037 	for (int i=start; i<cnt; i++) {
1038 		e.set(sk_X509_EXTENSION_value(st,i));
1039 		append(e);
1040 	}
1041 }
1042 
STACK_OF(X509_EXTENSION)1043 STACK_OF(X509_EXTENSION) *extList::getStack()
1044 {
1045 	STACK_OF(X509_EXTENSION) *sk = sk_X509_EXTENSION_new_null();
1046 	foreach(const x509v3ext &e, *this)
1047 		sk_X509_EXTENSION_push(sk, e.get());
1048 	return sk;
1049 }
1050 
search(const QRegExp & pattern)1051 bool extList::search(const QRegExp &pattern)
1052 {
1053 	foreach(const x509v3ext &e, *this)
1054 		if (e.getValue().contains(pattern))
1055 			return true;
1056 	return false;
1057 }
getHtml(const QString & sep)1058 QString extList::getHtml(const QString &sep)
1059 {
1060 	x509v3ext e;
1061 	QStringList s;
1062 	foreach(const x509v3ext &e, *this)
1063 		s << e.getHtml();
1064 	QString a = s.join(sep);
1065 	return a;
1066 }
1067 
getConsole(const QString & indent) const1068 QString extList::getConsole(const QString &indent) const
1069 {
1070 	x509v3ext e;
1071 	QStringList s;
1072 	foreach(const x509v3ext &e, *this)
1073 		s << e.getConsole(indent);
1074 	QString a = "\n" + s.join("\n");
1075 	return a;
1076 }
1077 
1078 
delByNid(int nid)1079 bool extList::delByNid(int nid)
1080 {
1081 	for(int i = 0; i< size(); i++) {
1082 		if (at(i).nid() == nid) {
1083 			removeAt(i);
1084 			return true;
1085 		}
1086 	}
1087 	return false;
1088 }
1089 
idxByNid(int nid)1090 int extList::idxByNid(int nid)
1091 {
1092 	for(int i = 0; i< size(); i++) {
1093 		if (at(i).nid() == nid) {
1094 			return i;
1095 		}
1096 	}
1097 	return -1;
1098 }
1099 
delInvalid(void)1100 int extList::delInvalid(void)
1101 {
1102 	int removed=0;
1103 	for(int i = 0; i<size(); i++) {
1104 		if (!at(i).isValid()) {
1105 			removeAt(i);
1106 			removed=1;
1107 			i--;
1108 		}
1109 	}
1110 	return removed;
1111 }
1112