1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2014 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 
9 #include <unistd.h>
10 #include "func.h"
11 #include "exception.h"
12 #include "lib/asn1time.h"
13 #include "lib/settings.h"
14 #include "widgets/validity.h"
15 #include "widgets/XcaWarning.h"
16 #include <openssl/objects.h>
17 #include <openssl/sha.h>
18 #include <openssl/asn1.h>
19 #include <openssl/err.h>
20 #include <openssl/bio.h>
21 #include <openssl/buffer.h>
22 
23 #if defined(Q_OS_MAC)
24 #include <IOKit/IOKitLib.h>
25   #if QT_VERSION < 0x050000
26 #include <QDesktopServices>
27   #else
28 #include <QStandardPaths>
29   #endif
30 #endif
31 #include <QDir>
32 #include <QFile>
33 #include <QFileInfo>
34 #include <QStringList>
35 #include <QLabel>
36 #include <QLineEdit>
37 #include <QComboBox>
38 #include <QMessageBox>
39 #include <QApplication>
40 #include <QPushButton>
41 #include <QProgressBar>
42 #include <QTextEdit>
43 #include <QDebug>
44 #include <stdarg.h>
45 
46 #if defined(Q_OS_WIN32)
47 #include <shlobj.h>
48 #include <conio.h>
49 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
50 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04
51 #endif
52 #else
53 #include <termios.h>
54 #define getch() getchar()
55 #endif
56 
console_write(FILE * fp,const QByteArray & ba)57 int console_write(FILE *fp, const QByteArray &ba)
58 {
59 	if (ba.size() == 0)
60 		return 0;
61 #if defined(Q_OS_WIN32)
62 	HANDLE con = GetStdHandle(fp == stderr ? STD_ERROR_HANDLE :
63 						 STD_OUTPUT_HANDLE);
64 	if (con != INVALID_HANDLE_VALUE) {
65 		QString string = QString::fromUtf8(ba);
66 		WriteConsoleW(con, string.utf16(), string.size(), NULL, NULL);
67 		//return 0;
68 	}
69 #endif
70 	fputs(ba.constData(), fp);
71 	fflush(fp);
72 	return 0;
73 }
74 
readPass()75 Passwd readPass()
76 {
77 	Passwd pw;
78 #if !defined(Q_OS_WIN32)
79 	struct termios t, back;
80 	if (tcgetattr(0, &t))
81 		throw errorEx(strerror(errno));
82 	back = t;
83 	t.c_lflag &= ~(ECHO | ICANON);
84 	if (tcsetattr(0, TCSAFLUSH, &t))
85 		throw errorEx(strerror(errno));
86 #else
87 	qFatal("Password input not supported");
88 #endif
89 	while(1) {
90 		char p = getch();
91 		if (p == '\n' || p == '\r')
92 			break;
93 		if (p == 0x7f)
94 			pw.chop(1);
95 		else
96 			pw += p;
97 	}
98 	fputc('\n', stdout);
99 #if !defined(Q_OS_WIN32)
100 	if (tcsetattr(0, TCSAFLUSH, &back))
101 		throw errorEx(strerror(errno));
102 #endif
103 	return pw;
104 }
105 
loadImg(const char * name)106 QPixmap *loadImg(const char *name )
107 {
108 	return new QPixmap(QString(":") + name);
109 }
110 
getLibExtensions()111 const QStringList getLibExtensions()
112 {
113 	return QStringList {
114 #if defined(Q_OS_WIN32)
115 		QString("*.dll"), QString("*.DLL"),
116 #elif defined(Q_OS_MAC)
117 		QString("*.dylib"), QString("*.so"),
118 #else
119 		QString("*.so"),
120 #endif
121 	};
122 }
123 
124 #if defined(Q_OS_WIN32)
xcaExeDir()125 static QString xcaExeDir()
126 {
127 	QString dir;
128 	wchar_t inst_dir[2048];
129 	ULONG dwLength = ARRAY_SIZE(inst_dir);
130 
131 	dwLength = GetModuleFileNameW(0, inst_dir, dwLength - 1);
132 	dir = QString::fromWCharArray(inst_dir, dwLength);
133 	int bslash = dir.lastIndexOf("\\");
134 	if (bslash > 0)
135 		dir = dir.mid(0, bslash);
136 	return QFileInfo(dir).canonicalFilePath();
137 }
138 
registryInstallDir()139 static QString registryInstallDir()
140 {
141 	QString dir;
142 	wchar_t inst_dir[2048] = L"";
143 	ULONG len = sizeof inst_dir;
144 
145 	if (RegGetValueW(HKEY_LOCAL_MACHINE, L"Software\\xca",
146 			L"Install_Dir64", RRF_RT_REG_SZ, NULL,
147 			inst_dir, &len) != ERROR_SUCCESS)
148 		return dir;
149 
150 	/* "len" is in octets */
151 	len /= sizeof inst_dir[0];
152 	/* "len" includes the trailing \0\0 */
153 	dir = QString::fromWCharArray(inst_dir, len -1);
154 	return QFileInfo(dir).canonicalFilePath();
155 }
156 #endif
157 
portable_app()158 int portable_app()
159 {
160 	static int portable = -1;
161 	QString f1, f2;
162 	if (portable == -1) {
163 #if defined(Q_OS_WIN32)
164 		f1 = registryInstallDir();
165 		f2 = xcaExeDir();
166 		/* f1 == f2 Registry entry of install dir exists and matches
167 		 * path of this xca.exe -> Installed. Not the portable app
168 		 */
169 		portable = f1 == f2 ? 0 : 1;
170 		qDebug() << "Portable:" << f1 << " != " << f2;
171 #else
172 		const char *p = getenv("XCA_PORTABLE");
173 		portable = p && *p;
174 #endif
175 	}
176 	return portable;
177 }
178 
179 /* returns e.g. /usr/local/share/xca for unix systems
180  * or HKEY_LOCAL_MACHINE->Software->xca for WIN32
181  * (e.g. c:\Program Files\xca )
182  */
183 
getPrefix()184 const QString getPrefix()
185 {
186 #if defined(Q_OS_WIN32)
187 	static QString inst_dir;
188 	QString reg_dir;
189 
190 	if (!inst_dir.isEmpty()) {
191 		/* if we already once discovered the directory just return it */
192 		return inst_dir;
193 	}
194 	inst_dir = xcaExeDir();
195 
196 	if (portable_app())
197 		return QString(inst_dir);
198 
199 	reg_dir = registryInstallDir();
200 	if (reg_dir.isEmpty())
201 		XCA_WARN("Registry Key: 'HKEY_LOCAL_MACHINE->Software->xca->Install_Dir' not found");
202 	else
203 		inst_dir = reg_dir;
204 	return inst_dir;
205 
206 #elif defined(Q_OS_MAC)
207 	// since this is platform-specific anyway,
208 	// this is a more robust way to get the bundle directory
209 	QDir bundleDir(qApp->applicationDirPath());
210 	bundleDir.cdUp();
211         return bundleDir.canonicalPath() + "/Resources";
212 #else
213 #ifndef XCA_PREFIX
214 #define XCA_PREFIX PREFIX "/share/xca"
215 #endif
216 	return QString(XCA_PREFIX);
217 #endif
218 
219 }
220 
221 #if defined(Q_OS_WIN32)
specialFolder(int csidl)222 static QString specialFolder(int csidl)
223 {
224 	LPITEMIDLIST pidl = NULL;
225 	wchar_t buf[MAX_PATH] = L"";
226 
227 	if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl, &pidl)))
228 		SHGetPathFromIDListW(pidl, buf);
229 
230 	QString f = QString::fromWCharArray(buf);
231 	qDebug() << "Special Folder" << csidl << f;
232 	return QFileInfo(f).canonicalFilePath();
233 }
234 #endif
235 
getHomeDir()236 const QString getHomeDir()
237 {
238 #if defined(Q_OS_WIN32)
239 	return portable_app() ? getPrefix() : specialFolder(CSIDL_PERSONAL);
240 #else
241 	return QDir::homePath();
242 #endif
243 }
244 
245 /* For portable APP remove leading file name if it is
246  * the app directory.
247  */
relativePath(QString path)248 QString relativePath(QString path)
249 {
250 	QFileInfo fi_path(path);
251 	QFileInfo fi_home(getHomeDir());
252 
253 	QString prefix = fi_home.absoluteFilePath();
254 	path = fi_path.absoluteFilePath();
255 
256 	if (portable_app()) {
257 		if (path.startsWith(prefix))
258 			path = path.mid(prefix.length()+1);
259 	}
260 	return path;
261 }
262 
getLibDir()263 const QString getLibDir()
264 {
265 #if defined(Q_OS_WIN32)
266 	return specialFolder(CSIDL_SYSTEM);
267 #else
268 	QString ulib = "/usr/lib/";
269 	QString lib = "/lib/";
270 	QString multi;
271 	QString hd = ulib;
272 
273 	QFile f(ulib + "pkg-config.multiarch");
274 	if (f.open(QIODevice::ReadOnly)) {
275 		QTextStream in(&f);
276 		multi = in.readLine();
277 		if (!multi.isEmpty())
278 			multi += "/";
279 	}
280 	QStringList dirs; dirs
281 		<< ulib + multi + "pkcs11/"
282 		<< lib + multi + "pkcs11/"
283 		<< ulib + "pkcs11/"
284 		<< lib + "pkcs11/"
285 		<< ulib + multi
286 		<< lib + multi
287 		<< ulib
288 		<< lib;
289 	foreach(QString dir, dirs) {
290 		if (QDir(dir).exists()) {
291 			hd = dir;
292 			break;
293 		}
294 	}
295 	return QFileInfo(hd).canonicalFilePath();
296 #endif
297 }
298 
getDocDir()299 const QString getDocDir()
300 {
301 #if defined(Q_OS_WIN32)
302 	return getPrefix() + "\\html";
303 #elif defined (Q_OS_MAC)
304 	return getPrefix();
305 #else
306 	return QString(DOCDIR);
307 #endif
308 }
309 
310 // The intent of this function is to return the proper location for
311 // user-controlled settings on the current platform
312 // i.e. PROFILE\Application Data\xca on windows, HOME/.xca on UNIX,
313 // ~/Library/Preferences/xca on Mac OS X
getUserSettingsDir()314 const QString getUserSettingsDir()
315 {
316 	QString rv;
317 #if defined(Q_OS_WIN32)
318 	rv = portable_app() ? getPrefix() + "/settings" :
319 				specialFolder(CSIDL_APPDATA) + "/xca";
320 #elif defined(Q_OS_MAC)
321   #if QT_VERSION < 0x050000
322 	rv = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
323 	rv.insert(rv.count() - QCoreApplication::applicationName().count(),
324 		QCoreApplication::organizationName());
325   #else
326 	rv = QStandardPaths::writableLocation(
327 			QStandardPaths::GenericDataLocation) + "/data/" +
328 		QCoreApplication::organizationName() + "/" +
329 		QCoreApplication::applicationName();
330   #endif
331 #else
332 	rv = QDir::homePath() + "/.xca";
333 #endif
334 	return rv;
335 }
336 
getI18nDir()337 const QString getI18nDir()
338 {
339 #if defined(Q_OS_WIN32)
340 	return getPrefix() + "\\i18n";
341 #else
342 	return getPrefix();
343 #endif
344 }
345 
346 // Qt's open and save dialogs result in some undesirable quirks.
347 // This function makes sure that a filename has the user-selected extension.
getFullFilename(const QString & filename,const QString & selectedFilter)348 QString getFullFilename(const QString & filename, const QString & selectedFilter)
349 {
350 	QString rv = filename.trimmed(), ext;
351 	QRegExp rx(".* \\( ?\\*(.[a-z]{1,3}) ?\\)");
352 	rx.indexIn(selectedFilter);
353 	ext = rx.cap(1);
354 	if (!ext.isEmpty() && !rv.endsWith(ext)) {
355 		rv += ext;
356 	}
357 	return rv;
358 }
359 
hostId()360 QString hostId()
361 {
362 	static QString id;
363 	unsigned char guid[100] = "", md[SHA_DIGEST_LENGTH];
364 
365 	if (!id.isEmpty())
366 		return id;
367 
368 #if defined(Q_OS_WIN32)
369 #define REG_CRYPTO "SOFTWARE\\Microsoft\\Cryptography"
370 #define REG_GUID "MachineGuid"
371 	ULONG dwGuid = sizeof guid;
372 	HKEY hKey;
373 
374 	if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, REG_CRYPTO, 0,
375 			KEY_READ, &hKey) != ERROR_SUCCESS) {
376 		XCA_WARN("Registry Key: '" REG_CRYPTO "' not found");
377 	} else {
378 		if (RegQueryValueExA(hKey, REG_GUID, NULL, NULL,
379 			guid, &dwGuid) != ERROR_SUCCESS) {
380 			XCA_WARN("Registry Key: '" REG_CRYPTO "\\" REG_GUID
381 				 "' not found");
382 		}
383 	}
384 	RegCloseKey(hKey);
385 
386 #elif defined(Q_OS_MAC)
387 	io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(
388 				kIOMasterPortDefault, "IOService:/");
389 	CFStringRef uuidCf = (CFStringRef)IORegistryEntryCreateCFProperty(
390 				ioRegistryRoot, CFSTR(kIOPlatformUUIDKey),
391 				kCFAllocatorDefault, 0);
392 
393 	snprintf((char*)guid, sizeof guid, "%s", CCHAR(
394 		QString::fromUtf16(CFStringGetCharactersPtr(uuidCf))
395 	));
396 
397 	IOObjectRelease(ioRegistryRoot);
398 	CFRelease(uuidCf);
399 
400 #else
401 	QString mach_id;
402 	QStringList dirs; dirs <<
403 			"/etc" << "/var/lib/dbus" << "/var/db/dbus";
404 	foreach(QString dir, dirs) {
405 		QFile file(dir + "/machine-id");
406 		if (file.open(QIODevice::ReadOnly)) {
407 			QTextStream in(&file);
408 			mach_id = in.readLine().trimmed();
409 			file.close();
410 		}
411 		qDebug() << "ID:" << mach_id;
412 		if (!mach_id.isEmpty()) {
413 			snprintf((char*)guid, sizeof guid, "%s", CCHAR(mach_id));
414 			break;
415 		}
416 	}
417 	if (mach_id.isEmpty())
418 		sprintf((char*)guid, "%ld", gethostid());
419 #endif
420 	guid[sizeof guid -1] = 0;
421 	SHA1(guid, strlen((char*)guid), md);
422 	id = QByteArray((char*)md, (int)sizeof md).toBase64().mid(0, 8);
423 
424 	qDebug() << "GUID:" << guid << "ID:" << id;
425 
426 	return id;
427 }
428 
compressFilename(const QString & filename,int maxlen)429 QString compressFilename(const QString &filename, int maxlen)
430 {
431 	QString fn = filename;
432 	if (fn.length() >= maxlen) {
433 		fn.replace("\\", "/");
434 		int len, lastslash = fn.lastIndexOf('/');
435 		QString base = filename.mid(lastslash);
436 		len = maxlen - base.length() - 3;
437 		if (len < 0) {
438 			fn = "..." + base.right(maxlen -3);
439 		} else {
440 			fn = fn.left(len);
441 			lastslash = fn.lastIndexOf('/');
442 			fn = filename.left(lastslash + 1) + "..." + base;
443 		}
444 	}
445 	return nativeSeparator(fn);
446 }
447 
asn1ToQString(const ASN1_STRING * str,bool quote)448 QString asn1ToQString(const ASN1_STRING *str, bool quote)
449 {
450 	QString qs;
451 	unsigned short *bmp;
452 	int i;
453 
454 	if (!str)
455 		return qs;
456 
457 	switch (str->type) {
458 		case V_ASN1_BMPSTRING:
459 			bmp = (unsigned short*)str->data;
460 			for (i = 0; i < str->length/2; i++) {
461 				unsigned short s = xntohs(bmp[i]);
462 				qs += QString::fromUtf16(&s, 1);
463 			}
464 			break;
465 		case V_ASN1_UTF8STRING:
466 			qs = QString::fromUtf8((const char*)str->data, str->length);
467 			break;
468 		case V_ASN1_T61STRING:
469 			qs = QString::fromLocal8Bit((const char*)str->data, str->length);
470 			break;
471 		default:
472 			qs = QString::fromLatin1((const char*)str->data, str->length);
473 	}
474 #if 0
475 	QString s;
476 	qDebug("Convert %s (%d %d) string to '%s' len %d:",
477 		ASN1_tag2str(str->type), str->type,
478 		V_ASN1_UTF8STRING, CCHAR(qs), str->length);
479 	for (int i=0; i< str->length; i++)
480 		s += QString(" %1").arg(str->data[i], 2, 16);
481 	qDebug() << s;
482 #endif
483 	if (quote)
484 		qs.replace('\n', "\\n\\");
485 	return qs;
486 }
487 
488 /* returns an encoded ASN1 string from QString for a special nid*/
QStringToAsn1(const QString s,int nid)489 ASN1_STRING *QStringToAsn1(const QString s, int nid)
490 {
491 	QByteArray ba = s.toUtf8();
492 	const unsigned char *utf8 = (const unsigned char *)ba.constData();
493 	unsigned long global_mask = ASN1_STRING_get_default_mask();
494 	unsigned long mask = DIRSTRING_TYPE & global_mask;
495 	ASN1_STRING *out = NULL;
496 	ASN1_STRING_TABLE *tbl;
497 
498 	tbl = ASN1_STRING_TABLE_get(nid);
499 	if (tbl) {
500 		mask = tbl->mask;
501 		if (!(tbl->flags & STABLE_NO_MASK))
502 			mask &= global_mask;
503 	}
504 	ASN1_mbstring_copy(&out, utf8, -1, MBSTRING_UTF8, mask);
505 	openssl_error(QString("'%1' (%2)").arg(s).arg(OBJ_nid2ln(nid)));
506 	return out;
507 }
508 
OBJ_ln2sn(const char * ln)509 const char *OBJ_ln2sn(const char *ln)
510 {
511 	return OBJ_nid2sn(OBJ_ln2nid(ln));
512 }
513 
OBJ_sn2ln(const char * sn)514 const char *OBJ_sn2ln(const char *sn)
515 {
516 	return OBJ_nid2ln(OBJ_sn2nid(sn));
517 }
518 
OBJ_obj2sn(ASN1_OBJECT * a)519 const char *OBJ_obj2sn(ASN1_OBJECT *a)
520 {
521 	OBJ_obj2nid(a);
522 	openssl_error();
523 	return OBJ_nid2sn(OBJ_obj2nid(a));
524 }
525 
OBJ_obj2QString(const ASN1_OBJECT * a,int no_name)526 QString OBJ_obj2QString(const ASN1_OBJECT *a, int no_name)
527 {
528 	char buf[512];
529 	int len;
530 
531 	len = OBJ_obj2txt(buf, sizeof buf, a, no_name);
532 	openssl_error();
533 	return QString::fromLatin1(buf, len);
534 }
535 
i2d_bytearray(int (* i2d)(const void *,unsigned char **),const void * data)536 QByteArray i2d_bytearray(int(*i2d)(const void*, unsigned char **),
537 		const void *data)
538 {
539 	QByteArray ba;
540 
541 	ba.resize(i2d(data, NULL));
542 	unsigned char *p = (unsigned char*)ba.data();
543 	i2d(data, &p);
544 	openssl_error();
545 	return ba;
546 }
547 
d2i_bytearray(void * (* d2i)(void *,unsigned char **,long),QByteArray & ba)548 void *d2i_bytearray(void *(*d2i)(void *, unsigned char **, long),
549 		QByteArray &ba)
550 {
551 	unsigned char *p, *p1;
552 	void *ret;
553 	p = p1 = (unsigned char *)ba.constData();
554 	ret = d2i(NULL, &p1, ba.count());
555 	ba = ba.mid(p1-p);
556 	openssl_error();
557 	return ret;
558 }
559 
_openssl_error(const QString & txt,const char * file,int line)560 void _openssl_error(const QString &txt, const char *file, int line)
561 {
562 	QString error;
563 
564 	while (int i = ERR_get_error() ) {
565 		error += QString(ERR_error_string(i, NULL)) + "\n";
566 		fputs(CCHAR(QString("OpenSSL error (%1:%2) : %3\n").
567 			arg(file).arg(line).arg(ERR_error_string(i, NULL))),
568 			stderr);
569 	}
570 	if (!error.isEmpty()) {
571 		if (!txt.isEmpty())
572 			error = txt + "\n" + error + "\n" +
573 				QString("(%1:%2)").arg(file).arg(line);
574 		throw errorEx(error);
575 	}
576 }
577 
578 #undef PRINT_IGNORED_ANYWAY
_ign_openssl_error(const QString & txt,const char * file,int line)579 bool _ign_openssl_error(const QString &txt, const char *file, int line)
580 {
581 	// ignore openssl errors
582 	QString errtxt;
583 #if PRINT_IGNORED_ANYWAY
584 	if (!txt.isEmpty() && ERR_peek_error())
585 		qDebug() << txt;
586 #else
587 	(void)txt;
588 	(void)file;
589 	(void)line;
590 #endif
591 	while (int i = ERR_get_error() ) {
592 		errtxt = ERR_error_string(i, NULL);
593 #if PRINT_IGNORED_ANYWAY
594 		qDebug() << QString("IGNORED (%1:%2) : %3\n")
595 				.arg(file).arg(line).arg(errtxt);
596 #endif
597 	}
598 	return !errtxt.isEmpty();
599 }
600 
formatHash(const QByteArray & data,QString sep,int width)601 QString formatHash(const QByteArray &data, QString sep, int width)
602 {
603 	return QString(data.toHex()).toUpper()
604 			.replace(QRegExp(QString("(.{%1})(?=.)").arg(width)),
605 				 QString("\\1") + sep);
606 }
607 
Digest(const QByteArray & data,const EVP_MD * type)608 QByteArray Digest(const QByteArray &data, const EVP_MD *type)
609 {
610 	unsigned int n;
611 	unsigned char m[EVP_MAX_MD_SIZE];
612 
613 	EVP_Digest(data.constData(), data.size(), m, &n, type, NULL);
614 	openssl_error();
615 	return QByteArray((char*)m, (int)n);
616 }
617 
fingerprint(const QByteArray & data,const EVP_MD * type)618 QString fingerprint(const QByteArray &data, const EVP_MD *type)
619 {
620 	return formatHash(Digest(data, type),
621 			Settings["fp_separator"], Settings["fp_digits"]);
622 }
623 
update_workingdir(const QString & file)624 void update_workingdir(const QString &file)
625 {
626 	Settings["workingdir"] = QFileInfo(file).absolutePath();
627 }
628 
629 QMap<int, QString> dn_translations;
630 
dn_translations_setup()631 void dn_translations_setup()
632 {
633 QMap<int, QString> D;
634 D[NID_countryName] = QObject::tr("Country code");
635 D[NID_stateOrProvinceName] = QObject::tr("State or Province");
636 D[NID_localityName] = QObject::tr("Locality");
637 D[NID_organizationName] = QObject::tr("Organisation");
638 D[NID_organizationalUnitName] = QObject::tr("Organisational unit");
639 D[NID_commonName] = QObject::tr("Common name");
640 D[NID_pkcs9_emailAddress] = QObject::tr("E-Mail address");
641 D[NID_serialNumber] = QObject::tr("Serial number");
642 D[NID_givenName] = QObject::tr("Given name");
643 D[NID_surname] = QObject::tr("Surname");
644 D[NID_title] = QObject::tr("Title");
645 D[NID_initials] = QObject::tr("Initials");
646 D[NID_description] = QObject::tr("Description");
647 D[NID_role] = QObject::tr("Role");
648 D[NID_pseudonym] = QObject::tr("Pseudonym");
649 D[NID_generationQualifier] = QObject::tr("Generation Qualifier");
650 D[NID_x500UniqueIdentifier] = QObject::tr("x500 Unique Identifier");
651 D[NID_name] = QObject::tr("Name");
652 D[NID_dnQualifier] = QObject::tr("DN Qualifier");
653 D[NID_pkcs9_unstructuredName] = QObject::tr("Unstructured name");
654 D[NID_pkcs9_challengePassword] = QObject::tr("Challenge password");
655 
656 D[NID_basic_constraints] = QObject::tr("Basic Constraints");
657 D[NID_subject_alt_name] = QObject::tr("Subject alternative name");
658 D[NID_issuer_alt_name] = QObject::tr("issuer alternative name");
659 D[NID_subject_key_identifier] = QObject::tr("Subject key identifier");
660 D[NID_authority_key_identifier] = QObject::tr("Authority key identifier");
661 D[NID_key_usage] = QObject::tr("Key usage");
662 D[NID_ext_key_usage] = QObject::tr("Extended key usage");
663 D[NID_crl_distribution_points] = QObject::tr("CRL distribution points");
664 D[NID_info_access] = QObject::tr("Authority information access");
665 D[NID_netscape_cert_type] = QObject::tr("Certificate type");
666 D[NID_netscape_base_url] = QObject::tr("Base URL");
667 D[NID_netscape_revocation_url] = QObject::tr("Revocation URL");
668 D[NID_netscape_ca_revocation_url] = QObject::tr("CA Revocation URL");
669 D[NID_netscape_renewal_url] = QObject::tr("Certificate renewal URL");
670 D[NID_netscape_ca_policy_url] = QObject::tr("CA policy URL");
671 D[NID_netscape_ssl_server_name] = QObject::tr("SSL server name");
672 D[NID_netscape_comment] = QObject::tr("Comment");
673 
674 dn_translations = D;
675 }
676 
appendXcaComment(QString current,QString msg)677 QString appendXcaComment(QString current, QString msg)
678 {
679 	if (!current.endsWith("\n") && !current.isEmpty())
680 		current += "\n";
681 	return current + QString("(%1)\n").arg(msg);
682 }
683