1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2014 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 #include "db_x509.h"
9 #include "pki_x509.h"
10 #include "pki_crl.h"
11 #include "pki_temp.h"
12 #include "pki_pkcs12.h"
13 #include "pki_pkcs7.h"
14 #include "pki_evp.h"
15 #include "pki_scard.h"
16 #include "pass_info.h"
17 #include "database_model.h"
18 #include "entropy.h"
19 
20 #include "widgets/XcaWarning.h"
21 #include "widgets/CertExtend.h"
22 #include "widgets/ExportDialog.h"
23 #include "widgets/MainWindow.h"
24 #include "widgets/PwDialog.h"
25 #include "widgets/RevocationList.h"
26 #include "widgets/NewX509.h"
27 #include "widgets/Help.h"
28 
29 #include "ui_CaProperties.h"
30 #include <QMessageBox>
31 #include <QContextMenuEvent>
32 #include <QAction>
33 
34 #include <openssl/rand.h>
35 
db_x509()36 db_x509::db_x509() : db_x509super("certificates")
37 {
38 	sqlHashTable = "certs";
39 	pkitype << x509;
40 	pkitype_depends << x509_req;
41 	updateHeaders();
42 	loadContainer();
43 }
44 
loadContainer()45 void db_x509::loadContainer()
46 {
47 	db_x509super::loadContainer();
48 
49 	XSqlQuery q("SELECT item, issuer FROM certs WHERE issuer is NOT NULL");
50 	while (q.next()) {
51 		pki_base *root = treeItem;
52 		pki_x509 *cert = Store.lookupPki<pki_x509>(q.value(0));
53 		pki_x509 *issuer = Store.lookupPki<pki_x509>(q.value(1));
54 		if (cert && issuer) {
55 			cert->setSigner(issuer);
56 			if (cert != issuer)
57 				root = issuer;
58 		}
59 		if (cert && cert->getParent() != root) {
60 			qDebug() << "MOVE" << cert->getIntName()
61 				<< "from" << cert->getParent()->getIntName()
62 				<< "to" << root->getIntName();
63 			insertChild(cert, root);
64 		}
65 	}
66 	emit columnsContentChanged();
67 }
68 
getHeaders()69 dbheaderList db_x509::getHeaders()
70 {
71 	dbheaderList h = db_x509super::getHeaders();
72 	h <<	new dbheader(HD_cert_ca, true, tr("CA"),
73 			tr("reflects the basic Constraints extension")) <<
74 		new num_dbheader(HD_cert_serial, true, tr("Serial")) <<
75 		new num_dbheader(HD_cert_md5fp, false,tr("MD5 fingerprint")) <<
76 		new num_dbheader(HD_cert_sha1fp,false,tr("SHA1 fingerprint")) <<
77 		new num_dbheader(HD_cert_sha256fp,false,tr("SHA256 fingerprint")) <<
78 		new date_dbheader(HD_cert_notBefore, false,tr("Start date"),
79 				tr("Not before")) <<
80 		new date_dbheader(HD_cert_notAfter, true, tr("Expiry date"),
81 				tr("Not after")) <<
82 		new date_dbheader(HD_cert_revocation,false, tr("Revocation")) <<
83 		new date_dbheader(HD_cert_crl_expire,true, tr("CRL Expiration"));
84 	return h;
85 }
86 
newPKI(enum pki_type type)87 pki_base *db_x509::newPKI(enum pki_type type)
88 {
89 	(void)type;
90 	return new pki_x509();
91 }
92 
getAllIssuers()93 QList<pki_x509 *> db_x509::getAllIssuers()
94 {
95 	/* Select X509 CA certificates with available private key */
96 	return Store.sqlSELECTpki<pki_x509>(
97 		"SELECT x509super.item FROM x509super "
98 		"JOIN private_keys ON x509super.pkey = private_keys.item "
99 		"JOIN certs ON certs.item = x509super.item "
100 		"WHERE certs.ca=1") +
101 		Store.sqlSELECTpki<pki_x509>(
102 		"SELECT x509super.item FROM x509super "
103 		"JOIN tokens ON x509super.pkey = tokens.item "
104 		"JOIN certs ON certs.item = x509super.item "
105 		"WHERE certs.ca=1");
106 }
107 
remFromCont(const QModelIndex & idx)108 void db_x509::remFromCont(const QModelIndex &idx)
109 {
110 	db_crl *crls = Database.model<db_crl>();
111 	db_x509super::remFromCont(idx);
112 	pki_base *pki = fromIndex(idx);
113 	pki_x509 *child;
114 	pki_base *new_parent;
115 	QList<pki_x509 *> childs;
116 
117 	while (pki->childCount()) {
118 		child = dynamic_cast<pki_x509*>(pki->takeFirst());
119 		child->delSigner(dynamic_cast<pki_x509*>(pki));
120 		new_parent = child->findIssuer();
121 		insertChild(child);
122 		if (new_parent)
123 			childs << child;
124 	}
125 	XSqlQuery q;
126 	SQL_PREPARE(q, "UPDATE certs SET issuer=? WHERE item=?");
127 	foreach(pki_x509 *child, childs) {
128 		q.bindValue(0, child->getSigner()->getSqlItemId());
129 		q.bindValue(1, child->getSqlItemId());
130 		AffectedItems(child->getSqlItemId());
131 		q.exec();
132 	}
133 	crls->removeSigner(pki);
134 }
135 
recursiveSigning(pki_x509 * cert,pki_x509 * client)136 static bool recursiveSigning(pki_x509 *cert, pki_x509 *client)
137 {
138 	/* recursive signing check */
139 	for (pki_x509 *s = cert->getSigner(); s; s = s->getSigner()) {
140 		if (s == s->getSigner()) {
141 			return false;
142 		}
143 		if (s == client) {
144 			qWarning() << "Recursive signing:" << s->getIntName()
145 				<< "<->" << cert->getIntName();
146 			return true;
147 		}
148 	}
149 	return false;
150 }
151 
inToCont(pki_base * pki)152 void db_x509::inToCont(pki_base *pki)
153 {
154 	pki_x509 *cert = dynamic_cast<pki_x509*>(pki);
155 	cert->setParent(NULL);
156 	pki_base *root = cert->getSigner();
157 
158 	insertChild(cert, root);
159 
160 	QList<pki_x509 *> childs;
161 	QList<pki_x509 *> items;
162 	unsigned pubhash = cert->pubHash();
163 	unsigned namehash = cert->getSubject().hashNum();
164 	x509revList revList;
165 
166 	/* Search for another certificate (name and key)
167 	 * and use its childs if we are newer */
168 	items = Store.sqlSELECTpki<pki_x509>(
169 		"SELECT x509super.item FROM x509super "
170 		"JOIN certs ON certs.item = x509super.item "
171 		"WHERE certs.ca=1 AND x509super.subj_hash=? "
172 		"AND x509super.key_hash=?",
173 			QList<QVariant>() << namehash << pubhash);
174 	foreach(pki_x509 *other, items) {
175 		if (other == cert)
176 			continue;
177 		if (!other->compareNameAndKey(cert))
178 			continue;
179 		if (cert->getNotAfter() < other->getNotAfter())
180 			continue;
181 		foreach(pki_base *b, other->getChildItems()) {
182 			pki_x509 *child = dynamic_cast<pki_x509*>(b);
183 			if (!child)
184 				continue;
185 			child->delSigner(other);
186 			childs << child;
187 		}
188 		revList.merge(other->getRevList());
189 	}
190 	/* Search rootItem childs, whether they are ours */
191 	foreach(pki_base *b, rootItem->getChildItems()) {
192 		pki_x509 *child = dynamic_cast<pki_x509*>(b);
193 		if (!child || child == cert || child->getSigner() == child)
194 			continue;
195 		if (child->verify_only(cert))
196 			childs << child;
197 	}
198 	/* move collected childs to us */
199 	XSqlQuery q;
200 	x509revList revokedChilds;
201 	SQL_PREPARE(q, "UPDATE certs SET issuer=? WHERE item=?");
202 	q.bindValue(0, cert->getSqlItemId());
203 	foreach(pki_x509 *child, childs) {
204 		if (recursiveSigning(cert, child))
205 			continue;
206 		if (!child->verify(cert))
207 			continue;
208 		insertChild(child, cert);
209 		q.bindValue(1, child->getSqlItemId());
210 		AffectedItems(child->getSqlItemId());
211 		q.exec();
212 		XCA_SQLERROR(q.lastError());
213 		if (child->isRevoked())
214 			revokedChilds << child->getRevocation();
215 	}
216 	q.finish();
217 	revList.merge(revokedChilds);
218 	cert->setRevocations(revList);
219 
220 	/* Update CRLs */
221 	QList<pki_crl *> crls = Store.sqlSELECTpki<pki_crl>(
222 			"SELECT item FROM crls WHERE iss_hash=?",
223 			QList<QVariant>() << namehash);
224 	SQL_PREPARE(q, "UPDATE crls SET issuer=? WHERE item=?");
225 	foreach(pki_crl *crl, crls) {
226 		crl->verify(cert);
227 		if (cert != crl->getIssuer())
228 			continue;
229 		q.bindValue(0, cert->getSqlItemId());
230 		q.bindValue(1, crl->getSqlItemId());
231 		AffectedItems(crl->getSqlItemId());
232 		q.exec();
233 		XCA_SQLERROR(q.lastError());
234 	}
235 }
236 
getCerts(bool unrevoked)237 QList<pki_x509*> db_x509::getCerts(bool unrevoked)
238 {
239 	QList<pki_x509*> c;
240 	c.clear();
241 	foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
242 		if (unrevoked && pki->isRevoked())
243 			continue;
244 		c.append(pki);
245 	}
246 	return c;
247 }
248 
writeIndex(const QString & fname,bool hierarchy) const249 void db_x509::writeIndex(const QString &fname, bool hierarchy) const
250 {
251 	if (hierarchy) {
252 		QString dir = fname + "/";
253 		if (!QDir().mkpath(fname)) {
254 			throw errorEx(tr("Failed to create directory '%1'")
255 				.arg(fname));
256 		}
257 		QList<pki_x509*> issuers = Store.sqlSELECTpki<pki_x509>(
258 			"SELECT DISTINCT issuer FROM certs WHERE issuer != item");
259 		foreach(pki_x509 *ca, issuers) {
260 			XFile file(dir + ca->getUnderlinedName() + ".txt");
261 			file.open_write();
262 			writeIndex(file, Store.sqlSELECTpki<pki_x509>(
263 				"SELECT item FROM certs WHERE issuer=?",
264 				QList<QVariant>()<<QVariant(ca->getSqlItemId()))
265 			);
266 		}
267 	} else {
268 		XFile file(fname);
269 		file.open_write();
270 		writeIndex(file, Store.sqlSELECTpki<pki_x509>(
271 					"SELECT item FROM certs"));
272 	}
273 }
274 
randomSerial()275 static a1int randomSerial()
276 {
277 	unsigned char buf[SHA512_DIGEST_LENGTH];
278 	unsigned char md[SHA512_DIGEST_LENGTH];
279 
280 	Entropy::seed_rng();
281 
282 	RAND_bytes(buf, SHA512_DIGEST_LENGTH);
283 	SHA512(buf, SHA512_DIGEST_LENGTH, md);
284 	a1int serial;
285 	if (md[0] && md[0] < 0x80)
286 		serial.setRaw(md, (int)Settings["serial_len"] / 8);
287 	return serial;
288 }
289 
getUniqueSerial(pki_x509 * signer)290 a1int db_x509::getUniqueSerial(pki_x509 *signer)
291 {
292 	// returns an unused unique serial
293 	a1int serial, signer_serial;
294 	x509rev rev;
295 	x509revList revList;
296 	if (signer) {
297 		signer_serial = signer->getSerial();
298 		revList = signer->getRevList();
299 	}
300 	for (int i=0; ; i++) {
301 		if (i > 100)
302 			throw errorEx(tr("Failed to retrieve unique random serial"));
303 		serial = randomSerial();
304 		if (serial == a1int(0L))
305 			continue;
306 		if (!signer)
307 			break;
308 		if (signer_serial == serial)
309 			continue;
310 		rev.setSerial(serial);
311 		if (revList.contains(rev))
312 			continue;
313 		if (signer->getBySerial(serial))
314 			continue;
315 		break;
316 	}
317 	return serial;
318 }
319 
insert(pki_base * item)320 pki_base *db_x509::insert(pki_base *item)
321 {
322 	pki_x509 *cert = dynamic_cast<pki_x509 *>(item);
323 	pki_x509 *oldcert = dynamic_cast<pki_x509 *>(getByReference(cert));
324 	if (oldcert) {
325 		XCA_INFO(tr("The certificate already exists in the database as:\n'%1'\nand so it was not imported").arg(oldcert->getIntName()));
326 		delete cert;
327 		return NULL;
328 	}
329 	return insertPKI(cert);
330 }
331 
load(void)332 void db_x509::load(void)
333 {
334 	load_cert c;
335 	load_default(c);
336 }
337 
get1SelectedCert()338 pki_x509 *db_x509::get1SelectedCert()
339 {
340 	QModelIndexList indexes = mainwin->certView->getSelectedIndexes();
341 	QModelIndex index;
342 	if (indexes.count())
343 		index = indexes[0];
344 	return fromIndex<pki_x509>(index);
345 }
346 
markRequestSigned(pki_x509req * req,pki_x509 * cert)347 void db_x509::markRequestSigned(pki_x509req *req, pki_x509 *cert)
348 {
349 	if (!req || !cert)
350 		return;
351 	pki_x509 *issuer = cert->getSigner();
352 
353 	Transaction;
354 	if (!TransBegin())
355 		return;
356 
357 	XSqlQuery q;
358 	req->setDone();
359 	SQL_PREPARE(q, "UPDATE requests SET signed=? WHERE item=?");
360 	q.bindValue(0, 1);
361 	q.bindValue(1, req->getSqlItemId());
362 	AffectedItems(req->getSqlItemId());
363 	q.exec();
364 
365 	a1time a;
366 	req->selfComment(tr("Signed on %1 by '%2'").arg(a.toPretty())
367 		.arg(issuer ? issuer->getIntName() : tr("Unknown")));
368 	SQL_PREPARE(q, "UPDATE items SET comment=? WHERE id=?");
369 	q.bindValue(0, req->getComment());
370 	q.bindValue(1, req->getSqlItemId());
371 	q.exec();
372 
373 	TransCommit();
374 }
375 
newItem()376 void db_x509::newItem()
377 {
378 	NewX509 *dlg = new NewX509();
379 	dlg->setCert();
380 	pki_x509 *sigcert = get1SelectedCert();
381 	dlg->defineSigner((pki_x509*)sigcert, true);
382 	if (dlg->exec()) {
383 		newCert(dlg);
384 	}
385 	delete dlg;
386 }
387 
newCert(pki_x509req * req)388 void db_x509::newCert(pki_x509req *req)
389 {
390 	NewX509 *dlg = new NewX509();
391 	pki_x509 *sigcert = get1SelectedCert();
392 	dlg->setCert();
393 	dlg->defineRequest(req);
394 	dlg->defineSigner(sigcert, true);
395 	if (dlg->exec()) {
396 		newCert(dlg);
397 	}
398 	delete dlg;
399 }
400 
newCert(pki_temp * temp)401 void db_x509::newCert(pki_temp *temp)
402 {
403 	NewX509 *dlg = new NewX509();
404 	dlg->setCert();
405 	dlg->defineTemplate(temp);
406 	if (dlg->exec()) {
407 		newCert(dlg);
408 	}
409 	delete dlg;
410 }
411 
newCert(pki_x509 * cert)412 void db_x509::newCert(pki_x509 *cert)
413 {
414 	NewX509 *dlg = new NewX509();
415 	dlg->setCert();
416 	dlg->fromX509super(cert, false);
417 	if (dlg->exec()) {
418 		newCert(dlg);
419 	}
420 	delete dlg;
421 }
422 
newCert(NewX509 * dlg)423 pki_x509 *db_x509::newCert(NewX509 *dlg)
424 {
425 	pki_x509 *cert = NULL;
426 	pki_x509 *signcert = NULL;
427 	pki_x509req *req = NULL;
428 	pki_key *signkey = NULL, *clientkey = NULL, *tempkey = NULL;
429 	a1int serial;
430 	QString intname;
431 
432     try {
433 	Transaction;
434 	// Step 1 - Subject and key
435 	if (!dlg->fromReqCB->isChecked()) {
436 		clientkey = dlg->getSelectedKey();
437 		if (!clientkey)
438 			return NULL;
439 		intname = dlg->description->text();
440 	} else {
441 		// A PKCS#10 Request was selected
442 		req = dlg->getSelectedReq();
443 		if (!req)
444 			return NULL;
445 		clientkey = req->getRefKey();
446 		if (clientkey == NULL) {
447 			clientkey = req->getPubKey();
448 			tempkey = clientkey;
449 		}
450 		intname = req->getIntName();
451 	}
452 	TransThrow();
453 
454 	if (clientkey == NULL)
455 		throw errorEx(tr("Invalid public key"));
456 	// initially create cert
457 	cert = new pki_x509();
458 	cert->setIntName(intname);
459 	cert->setSubject(dlg->getX509name());
460 	cert->setPubKey(clientkey);
461 
462 	// Step 2 - select Signing
463 	if (dlg->foreignSignRB->isChecked()) {
464 		signcert = dlg->getSelectedSigner();
465 		if (!signcert) {
466 			delete cert;
467 			return NULL;
468 		}
469 		serial = getUniqueSerial(signcert);
470 		signkey = signcert->getRefKey();
471 	} else {
472 		signcert = cert;
473 		signkey = clientkey;
474 		serial = getUniqueSerial(NULL);
475 	}
476 
477 	dlg->initCtx(cert, signcert, NULL);
478 	// if we can not sign
479 	if (! signkey || signkey->isPubKey()) {
480 		delete cert;
481 		throw errorEx(tr("The key you selected for signing is not a private one."));
482 	}
483 
484 	// set the issuers name
485 	cert->setIssuer(signcert->getSubject());
486 	cert->setSerial(serial);
487 
488 	// Step 3 - Choose the Date
489 	// Date handling
490 	cert->setNotBefore(dlg->notBefore->getDate());
491 	a1time a;
492 	if (dlg->noWellDefinedExpDate->isChecked())
493 		a.setUndefined();
494 	else
495 		a = dlg->notAfter->getDate();
496 
497 	cert->setNotAfter(a);
498 
499 	// STEP 4 handle extensions
500 
501 	// apply all extensions to the subject cert in the context
502 	dlg->getAllExt();
503 
504 	// apply extensions from CSR if requested
505 	if (dlg->copyReqExtCB->isChecked() && dlg->fromReqCB->isChecked()) {
506 		extList el = req->getV3ext();
507 		int m = el.count();
508 		for (int i=0; i<m; i++)
509 			cert->addV3ext(el[i], true);
510 	}
511 
512 	const EVP_MD *hashAlgo = dlg->hashAlgo->currentHash();
513 	// and finally sign the request
514 	cert->sign(signkey, hashAlgo);
515 
516 	// set the comment field
517 	cert->setComment(dlg->comment->toPlainText());
518 	cert->pkiSource = dlg->getPkiSource();
519 	cert = dynamic_cast<pki_x509*>(insert(cert));
520 	createSuccess(cert);
521 	if (cert && clientkey->isToken()) {
522 		pki_scard *card = (pki_scard*)clientkey;
523 		if (XCA_YESNO(tr("Store the certificate to the key on the token '%1 (#%2)' ?").
524 			arg(card->getCardLabel()).arg(card->getSerial())))
525 		{
526 			try {
527 				cert->store_token(false);
528 			} catch (errorEx &err) {
529 				XCA_ERROR(err);
530 			}
531 		}
532 	}
533 	delete tempkey;
534 	markRequestSigned(req, cert);
535 	TransCommit();
536     }
537 
538     catch (errorEx &err) {
539 		XCA_ERROR(err);
540 		delete cert;
541 		if (tempkey != NULL)
542 			delete(tempkey);
543 		cert = NULL;
544     }
545     return cert;
546 }
547 
store(QModelIndex idx)548 void db_x509::store(QModelIndex idx)
549 {
550 	QModelIndexList l;
551 	l << idx;
552 	store(l);
553 }
554 
store(QModelIndexList list)555 void db_x509::store(QModelIndexList list)
556 {
557 	QStringList filt;
558 	bool chain;
559 	QList<exportType> types, usual;
560 
561 	if (list.size() == 0)
562 		return;
563 
564 	pki_x509 *oldcrt, *crt = fromIndex<pki_x509>(list[0]);
565 	if (!crt)
566 		return;
567 
568 	pki_key *privkey = crt->getRefKey();
569 	pki_evp *pkey;
570 	chain = crt->getSigner() && crt->getSigner() != crt;
571 
572 	usual <<
573 		exportType(exportType::PEM, "crt", "PEM") <<
574 		exportType(exportType::PKCS7, "p7b", "PKCS #7");
575 
576 	types << exportType(exportType::DER, "cer", "DER");
577 
578 	if (list.size() > 1) {
579 		usual <<
580 			exportType(exportType::PEM_selected, "pem",
581 				"PEM selected") <<
582 			exportType(exportType::PKCS7_selected, "pem",
583 				"PKCS7 selected");
584 	}
585 	if (chain) {
586 		types <<
587 			exportType(exportType::PEM_chain, "pem",
588 				tr("PEM chain")) <<
589 			exportType(exportType::PKCS7_chain, "p7b",
590 				tr("PKCS#7 chain"));
591 	}
592 
593 	if (privkey && privkey->isPrivKey() && !privkey->isToken()) {
594 		if (chain) {
595 			usual << exportType(exportType::PKCS12_chain, "pfx",
596 				tr("PKCS#12 chain"));
597 			types << exportType(exportType::PKCS12, "pfx",
598 				"PKCS #12");
599 		} else {
600 			usual << exportType(exportType::PKCS12, "pfx",
601 				"PKCS #12");
602 		}
603 		types <<
604 			exportType(exportType::PEM_cert_key, "pem",
605 				tr("PEM + key")) <<
606 			exportType(exportType::PEM_cert_pk8, "pem",
607 				"PEM + PKCS#8");
608 	}
609 	types << exportType() <<
610 		exportType(exportType::PKCS7_unrevoked, "p7b",
611 			tr("PKCS#7 unrevoked")) <<
612 		exportType(exportType::PKCS7_all, "p7b",
613 			tr("PKCS#7 all")) <<
614 		exportType(exportType::PEM_unrevoked, "pem",
615 			tr("PEM unrevoked")) <<
616 		exportType(exportType::PEM_all, "pem",
617 			tr("PEM all")) <<
618 		exportType(exportType::Index, "txt",
619 			tr("Certificate Index file"));
620 	if (crt->getNotAfter() > a1time())
621 		types << exportType(exportType::vcalendar, "ics",
622 			tr("vCalendar"));
623 
624 	if (crt->isCA())
625 		types << exportType(exportType::vcalendar_ca, "ics",
626 			tr("CA vCalendar"));
627 
628 	types = usual << exportType() << types;
629 	ExportDialog *dlg = new ExportDialog(NULL, tr("Certificate export"),
630 		tr("X509 Certificates ( *.pem *.cer *.crt *.p12 *.pfx *.p7b )"), crt,
631 		QPixmap(":certImg"), types, "certexport");
632 	if (!dlg->exec()) {
633 		delete dlg;
634 		return;
635 	}
636 	QStringList vcal;
637 	QList<pki_x509*> certs;
638 	QList<pki_base*> items;
639 	enum exportType::etype type = dlg->type();
640 	try {
641 		XFile file(dlg->filename->text());
642 		file.open_write();
643 		pki_base::pem_comment = dlg->pemComment->isChecked();
644 
645 		switch (type) {
646 		case exportType::PEM:
647 			crt->writeCert(file, true);
648 			break;
649 		case exportType::PEM_chain:
650 			while (crt && crt != oldcrt) {
651 				crt->writeCert(file, true);
652 				oldcrt = crt;
653 				crt = crt->getSigner();
654 			}
655 			break;
656 		case exportType::PEM_selected:
657 			foreach(QModelIndex idx, list) {
658 				crt = fromIndex<pki_x509>(idx);
659 				if (crt)
660 					crt->writeCert(file, true);
661 			}
662 			break;
663 		case exportType::PEM_unrevoked:
664 			foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
665 				if (!pki->isRevoked())
666 					pki->writeCert(file, true);
667 			}
668 			break;
669 		case exportType::PEM_all:
670 			foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
671 				pki->writeCert(file, true);
672 			}
673 			break;
674 		case exportType::DER:
675 			crt->writeCert(file, false);
676 			break;
677 		case exportType::PKCS7:
678 		case exportType::PKCS7_chain:
679 		case exportType::PKCS7_unrevoked:
680 		case exportType::PKCS7_selected:
681 		case exportType::PKCS7_all:
682 			writePKCS7(crt, file, type, list);
683 			break;
684 		case exportType::PKCS12:
685 			writePKCS12(crt, file, false);
686 			break;
687 		case exportType::PKCS12_chain:
688 			writePKCS12(crt, file, true);
689 			break;
690 		case exportType::PEM_cert_pk8:
691 		case exportType::PEM_cert_key:
692 			pkey = (pki_evp *)crt->getRefKey();
693 			if (!pkey || pkey->isPubKey()) {
694 				XCA_WARN(tr("There was no key found for the Certificate: '%1'").
695 					arg(crt->getIntName()));
696 				break;
697 			}
698 			if (pkey->isToken()) {
699 				XCA_WARN(tr("Not possible for a token key: '%1'").
700 					arg(crt->getIntName()));
701 				break;
702 			}
703 
704 			if (type == exportType::PEM_cert_pk8) {
705 				pkey->writePKCS8(file, EVP_des_ede3_cbc(),
706 						PwDialog::pwCallback, true);
707 			} else {
708 				pkey->writeKey(file, NULL, NULL, true);
709 			}
710 			crt->writeCert(file, true);
711 			break;
712 		case exportType::Index:
713 			foreach(QModelIndex idx, list) {
714 				crt = fromIndex<pki_x509>(idx);
715 				if (crt)
716 					certs << crt;
717 			}
718 			writeIndex(file, certs);
719 			break;
720 		case exportType::vcalendar:
721 			foreach(QModelIndex idx, list) {
722 				crt = fromIndex<pki_x509>(idx);
723 				if (crt)
724 					vcal += crt->icsVEVENT();
725 			}
726 			writeVcalendar(file, vcal);
727 			break;
728 		case exportType::vcalendar_ca:
729 			foreach(QModelIndex idx, list) {
730 				crt = fromIndex<pki_x509>(idx);
731 				if (crt)
732 					vcal += crt->icsVEVENT_ca();
733 			}
734 			writeVcalendar(file, vcal);
735 			break;
736 		default:
737 			exit(1);
738 		}
739 	}
740 	catch (errorEx &err) {
741 		XCA_ERROR(err);
742 	}
743 	pki_base::pem_comment = false;
744 	delete dlg;
745 }
746 
writeIndex(XFile & file,QList<pki_x509 * > items) const747 void db_x509::writeIndex(XFile &file, QList<pki_x509*> items) const
748 {
749 	QString index;
750 	foreach(pki_x509 *cert, items) {
751 		if (cert)
752 			index += cert->getIndexEntry();
753 	}
754 	file.write(index.toUtf8());
755 }
756 
writePKCS12(pki_x509 * cert,XFile & file,bool chain) const757 void db_x509::writePKCS12(pki_x509 *cert, XFile &file, bool chain) const
758 {
759 	QStringList filt;
760 	pki_pkcs12 *p12 = NULL;
761 	try {
762 		pki_evp *privkey = (pki_evp *)cert->getRefKey();
763 		if (!privkey || privkey->isPubKey()) {
764 			XCA_WARN(tr("There was no key found for the Certificate: '%1'").arg(cert->getIntName()));
765 			return;
766 		}
767 		if (privkey->isToken()) {
768 			XCA_WARN(tr("Not possible for the token-key Certificate '%1'").arg(cert->getIntName()));
769 			return;
770 		}
771 		p12 = new pki_pkcs12(cert->getIntName(), cert, privkey);
772 		pki_x509 *signer = cert->getSigner();
773 		while ((signer != NULL ) && (signer != cert) && chain) {
774 			p12->append_item(signer);
775 			cert = signer;
776 			signer = signer->getSigner();
777 		}
778 		p12->writePKCS12(file);
779 	}
780 	catch (errorEx &err) {
781 		XCA_ERROR(err);
782 	}
783 	delete p12;
784 }
785 
writePKCS7(pki_x509 * cert,XFile & file,exportType::etype type,QModelIndexList list) const786 void db_x509::writePKCS7(pki_x509 *cert, XFile &file, exportType::etype type,
787 			QModelIndexList list) const
788 {
789 	pki_pkcs7 *p7 = NULL;
790 
791 	try {
792 		p7 = new pki_pkcs7(QString());
793 		switch (type) {
794 		case exportType::PKCS7_chain:
795 			while (cert != NULL) {
796 				p7->append_item(cert);
797 				if (cert->getSigner() == cert)
798 					cert = NULL;
799 				else
800 					cert = cert->getSigner();
801 			}
802 			break;
803 		case exportType::PKCS7:
804 			p7->append_item(cert);
805 			break;
806 		case exportType::PKCS7_selected:
807 			foreach(QModelIndex idx, list) {
808 				cert = fromIndex<pki_x509>(idx);
809 				if (cert)
810 					p7->append_item(cert);
811 			}
812 			break;
813 		case exportType::PKCS7_unrevoked:
814 		case exportType::PKCS7_all:
815 			foreach(pki_x509 *cer, Store.getAll<pki_x509>()) {
816 				if ((type == exportType::PKCS7_all) ||
817 				    (!cer->isRevoked()))
818 					p7->append_item(cer);
819 			}
820 			break;
821 		default:
822 			exit(1);
823 		}
824 		p7->writeP7(file, false);
825 	}
826 	catch (errorEx &err) {
827 		XCA_ERROR(err);
828 	}
829 	delete p7;
830 }
831 
certRenewal(QModelIndexList indexes)832 void db_x509::certRenewal(QModelIndexList indexes)
833 {
834 	pki_x509 *oldcert = NULL, *signer = NULL, *newcert =NULL;
835 	pki_key *signkey = NULL;
836 	a1time time;
837 	a1int serial;
838 	CertExtend *dlg = NULL;
839 	x509rev r;
840 	bool doRevoke = false;
841 
842 	if (indexes.size() == 0)
843 		return;
844 	QModelIndex idx = indexes[0];
845 
846 	try {
847 		oldcert = fromIndex<pki_x509>(idx);
848 		if (!oldcert || !(signer = oldcert->getSigner()) ||
849 				!(signkey = signer->getRefKey()) ||
850 				signkey->isPubKey())
851 			return;
852 		bool renew_myself = signer == oldcert;
853 		CertExtend *dlg = new CertExtend(NULL,
854 					renew_myself ? NULL : signer);
855 		dlg->revoke->setEnabled(!renew_myself);
856 		if (!dlg->exec()) {
857 			delete dlg;
858 			return;
859 		}
860 		if (dlg->revoke->isChecked() && !renew_myself) {
861 			Revocation *revoke = new Revocation(indexes);
862 			doRevoke = revoke->exec();
863 			r = revoke->getRevocation();
864 			delete revoke;
865 		}
866 		foreach(idx, indexes) {
867 			oldcert = fromIndex<pki_x509>(idx);
868 			if (!oldcert)
869 				continue;
870 			newcert = new pki_x509(oldcert);
871 			newcert->pkiSource = renewed;
872 			serial = dlg->keepSerial->isChecked() ?
873 				oldcert->getSerial() : getUniqueSerial(signer);
874 			newcert->setRevoked(x509rev());
875 
876 			// change date and serial
877 			newcert->setSerial(serial);
878 			newcert->setNotBefore(dlg->notBefore->getDate());
879 			a1time a;
880 			if (dlg->noWellDefinedExpDate->isChecked())
881 				a.setUndefined();
882 			else
883 				a = dlg->notAfter->getDate();
884 
885 			newcert->setNotAfter(a);
886 
887 			// and finally sign the cert
888 			newcert->sign(signkey, oldcert->getDigest());
889 			newcert = dynamic_cast<pki_x509 *>(insert(newcert));
890 			createSuccess(newcert);
891 		}
892 		if (doRevoke)
893 			do_revoke(indexes, r);
894 	}
895 	catch (errorEx &err) {
896 		XCA_ERROR(err);
897 		delete newcert;
898 	}
899 	delete dlg;
900 	emit columnsContentChanged();
901 }
902 
903 
revoke(QModelIndexList indexes)904 void db_x509::revoke(QModelIndexList indexes)
905 {
906 	if (indexes.size() == 0)
907 		return;
908 	Revocation *revoke = new Revocation(indexes);
909 	if (revoke->exec()) {
910 		do_revoke(indexes, revoke->getRevocation());
911 	}
912 	emit columnsContentChanged();
913 }
914 
do_revoke(QModelIndexList indexes,const x509rev & r)915 void db_x509::do_revoke(QModelIndexList indexes, const x509rev &r)
916 {
917 	pki_x509 *parent = NULL, *cert, *iss;
918 	x509revList revlist;
919 
920 	foreach(QModelIndex idx, indexes) {
921 		cert = fromIndex<pki_x509>(idx);
922 		if (!cert)
923 			continue;
924 		iss = cert->getSigner();
925 		if (parent == NULL) {
926 			parent = iss;
927 		} else if (parent != iss) {
928 			parent = NULL;
929 			break;
930 		}
931 	}
932 	if (!parent) {
933 		qWarning("%s(%d): Certs have different/no signer",
934 			 __func__, __LINE__);
935 	}
936 	foreach(QModelIndex idx, indexes) {
937 		cert = fromIndex<pki_x509>(idx);
938 		if (!cert)
939 			continue;
940 		x509rev rev(r);
941 		rev.setSerial(cert->getSerial());
942 		cert->setRevoked(rev);
943 		revlist << rev;
944 	}
945 	parent->mergeRevList(revlist);
946 }
947 
unRevoke(QModelIndexList indexes)948 void db_x509::unRevoke(QModelIndexList indexes)
949 {
950 	pki_x509 *parent = NULL;
951 	x509revList revList;
952 
953 	foreach(QModelIndex idx, indexes) {
954 		pki_x509 *cert = fromIndex<pki_x509>(idx);
955 		if (!cert)
956 			continue;
957 		pki_x509 *iss = cert->getSigner();
958 		if (parent == NULL) {
959 			parent = iss;
960 		} else if (parent != iss) {
961 			parent = NULL;
962 			break;
963 		}
964 	}
965 	if (!parent) {
966 		qWarning("%s(%d): Certs have different/no issuer\n",
967 			 __func__, __LINE__);
968 		return;
969 	}
970 	revList = parent->getRevList();
971 
972 	foreach(QModelIndex idx, indexes) {
973 		int i;
974 		x509rev rev;
975 		pki_x509 *cert = fromIndex<pki_x509>(idx);
976 
977 		if (!cert)
978 			continue;
979 
980 		cert->setRevoked(x509rev());
981 		rev.setSerial(cert->getSerial());
982 		i = revList.indexOf(rev);
983 		if (i != -1)
984 			revList.takeAt(i);
985 	}
986 	parent->setRevocations(revList);
987 	emit columnsContentChanged();
988 }
989 
toCertificate(QModelIndex index)990 void db_x509::toCertificate(QModelIndex index)
991 {
992 	pki_x509 *cert = fromIndex<pki_x509>(index);
993 	if (!cert)
994 		return;
995 	if (!cert->getRefKey() && cert->getSigner() != cert)
996 		extractPubkey(index);
997 	cert->pkiSource = transformed;
998 	newCert(cert);
999 }
1000 
toRequest(QModelIndex idx)1001 void db_x509::toRequest(QModelIndex idx)
1002 {
1003 	db_x509req *reqs = Database.model<db_x509req>();
1004 	pki_x509 *cert = fromIndex<pki_x509>(idx);
1005 	if (!cert)
1006 		return;
1007 
1008 	try {
1009 		pki_x509req *req = new pki_x509req();
1010 		check_oom(req);
1011 		req->pkiSource = transformed;
1012 		req->setIntName(cert->getIntName());
1013 		req->createReq(cert->getRefKey(), cert->getSubject(),
1014 			cert->getDigest(), cert->getV3ext());
1015 		createSuccess(reqs->insert(req));
1016 	}
1017 	catch (errorEx &err) {
1018 		XCA_ERROR(err);
1019 	}
1020 }
1021 
toToken(QModelIndex idx,bool alwaysSelect)1022 void db_x509::toToken(QModelIndex idx, bool alwaysSelect)
1023 {
1024 	pki_x509 *cert = fromIndex<pki_x509>(idx);
1025 	if (!cert)
1026 		return;
1027 	try {
1028 		cert->store_token(alwaysSelect);
1029 	} catch (errorEx &err) {
1030 		XCA_ERROR(err);
1031         }
1032 }
1033 
caProperties(QModelIndex idx)1034 void db_x509::caProperties(QModelIndex idx)
1035 {
1036 	QStringList actions;
1037 	Ui::CaProperties ui;
1038 
1039 	pki_x509 *cert = fromIndex<pki_x509>(idx);
1040 	if (!cert)
1041 		return;
1042 
1043 	QDialog *dlg = new QDialog(NULL);
1044 	ui.setupUi(dlg);
1045 	ui.days->setSuffix(QString(" ") + tr("days"));
1046 	ui.days->setMaximum(1000000);
1047 	ui.days->setValue(cert->getCrlDays());
1048 	ui.image->setPixmap(QPixmap(":certImg"));
1049 
1050 	QVariant tmplId = cert->getTemplateSqlId();
1051 	pki_temp *templ = Store.lookupPki<pki_temp>(tmplId);
1052 
1053 	ui.temp->insertPkiItems(Store.getAll<pki_temp>());
1054         ui.temp->setNullItem(tr("No template"));
1055 	ui.temp->setCurrentIndex(0);
1056 	if (templ)
1057 		ui.temp->setCurrentPkiItem(templ);
1058 
1059 	ui.certName->setTitle(cert->getIntName());
1060 	mainwin->helpdlg->register_ctxhelp_button(dlg, "ca_properties");
1061 
1062 	if (dlg->exec()) {
1063 		XSqlQuery q;
1064 		QSqlError e;
1065 		Transaction;
1066 		TransThrow();
1067 
1068 		templ = ui.temp->currentPkiItem();
1069 		tmplId = templ ? templ->getSqlItemId() : QVariant();
1070 
1071 		cert->setTemplateSqlId(tmplId);
1072 		cert->setCrlDays(ui.days->value());
1073 
1074 		SQL_PREPARE(q, "UPDATE authority SET crlDays=?, "
1075 				"template=? WHERE item=?");
1076 
1077 		q.bindValue(0, cert->getCrlDays());
1078 		q.bindValue(1, tmplId);
1079 		q.bindValue(2, cert->getSqlItemId());
1080 		AffectedItems(cert->getSqlItemId());
1081 		q.exec();
1082 	        TransDone(q.lastError());
1083 		XCA_SQLERROR(q.lastError());
1084 	}
1085 	delete dlg;
1086 }
1087