1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2015 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 #include "RevocationList.h"
9 #include "MainWindow.h"
10 #include "NewCrl.h"
11 #include "Help.h"
12 #include "lib/asn1int.h"
13 #include "lib/pki_x509.h"
14 
15 enum revCol { Cnumber, Cserial, Cdate, Creason, CiDate, Cmax };
16 
17 class revListItem : public QTreeWidgetItem
18 {
19     public:
revListItem(QTreeWidget * w)20 	revListItem(QTreeWidget *w) : QTreeWidgetItem(w) { };
operator <(const QTreeWidgetItem & other) const21 	bool operator < (const QTreeWidgetItem &other) const
22 	{
23 		int col = treeWidget()->sortColumn();
24 		switch (col) {
25 		case Cserial: {
26 			return a1int(text(Cserial)) <
27 				a1int(other.text(Cserial));
28 		}
29 		case Cnumber:
30 			return text(Cnumber).toLong() <
31 				other.text(Cnumber).toLong();
32 		default:
33 			return QTreeWidgetItem::operator < (other);
34 		}
35 	}
36 };
37 
setup_revRevItem(QTreeWidgetItem * item,const x509rev & revit,const pki_x509 * iss)38 static void setup_revRevItem(QTreeWidgetItem *item, const x509rev &revit,
39 			const pki_x509 *iss)
40 {
41 	pki_x509 *rev = iss ? iss->getBySerial(revit.getSerial()) : NULL;
42 	if (rev != NULL) {
43 		for (int i = 0; i < Cmax; i++)
44 			item->setToolTip(i, rev->getIntName());
45 	}
46 	item->setText(Cserial, revit.getSerial());
47 	item->setText(Cdate, revit.getDate().toSortable());
48 	item->setText(Creason, revit.getReason());
49 
50 	item->setTextAlignment(Cnumber, Qt::AlignRight);
51 	item->setTextAlignment(Cserial, Qt::AlignRight);
52 
53 	a1time a = revit.getInvalDate();
54 	if (!a.isUndefined())
55 		item->setText(CiDate, a.toSortable());
56 }
57 
addRevItem(QTreeWidget * certList,const x509rev & revit,int no,const pki_x509 * iss)58 static void addRevItem(QTreeWidget *certList, const x509rev &revit,
59 			int no, const pki_x509 *iss)
60 {
61 	revListItem *current;
62 	current = new revListItem(certList);
63 	current->setText(Cnumber, QString("%1").arg(no));
64 	setup_revRevItem(current, revit, iss);
65 }
66 
setupRevocationView(QTreeWidget * certList,const x509revList & revList,const pki_x509 * iss)67 void RevocationList::setupRevocationView(QTreeWidget *certList,
68 			const x509revList &revList, const pki_x509 *iss)
69 {
70 	QStringList sl;
71 	int cols, i;
72 
73 	certList->clear();
74 
75 	sl << tr("No.") << tr("Serial") << tr("Revocation") << tr("Reason") <<
76 		tr("Invalidation");
77 
78 	cols = sl.size();
79 	certList->setColumnCount(cols);
80 	certList->setHeaderLabels(sl);
81 	certList->setItemsExpandable(false);
82 	certList->setRootIsDecorated(false);
83 	certList->sortItems(Cnumber, Qt::AscendingOrder);
84 
85 	i=1;
86 	foreach(x509rev revit, revList) {
87 		addRevItem(certList, revit, i++, iss);
88 	}
89 	for (i=0; i<cols; i++)
90 		certList->resizeColumnToContents(i);
91 	certList->setSortingEnabled(true);
92 	certList->setSelectionBehavior(QAbstractItemView::SelectRows);
93 	certList->setSelectionMode(QAbstractItemView::ExtendedSelection);
94 }
95 
RevocationList(QWidget * w)96 RevocationList::RevocationList(QWidget *w) : QDialog(w ?: mainwin)
97 {
98 	QPushButton *genCrl;
99 	setupUi(this);
100 	setWindowTitle(XCA_TITLE);
101 	image->setPixmap(QPixmap(":revImg"));
102 	mainwin->helpdlg->register_ctxhelp_button(this, "crlmanage");
103 
104 	genCrl = buttonBox->addButton(tr("Generate CRL"),
105 				QDialogButtonBox::ActionRole);
106 
107 	connect(genCrl, SIGNAL(clicked()), this, SLOT(gencrl()));
108 }
109 
gencrl()110 void RevocationList::gencrl()
111 {
112 	issuer->setRevocations(getRevList());
113 	NewCrl::newCrl(this, issuer);
114 }
115 
setRevList(const x509revList & rl,pki_x509 * iss)116 void RevocationList::setRevList(const x509revList &rl, pki_x509 *iss)
117 {
118 	issuer = iss;
119 	revList = rl;
120 	setupRevocationView(certList, revList, issuer);
121 }
122 
getRevList()123 const x509revList &RevocationList::getRevList()
124 {
125 	return revList;
126 }
127 
on_addRev_clicked()128 void RevocationList::on_addRev_clicked()
129 {
130 	Revocation *revoke = new Revocation(QModelIndexList(), this);
131         if (revoke->exec()) {
132 		x509rev revit = revoke->getRevocation();
133 		revList << revit;
134 		addRevItem(certList, revit, revList.size(), issuer);
135 	}
136 }
137 
on_delRev_clicked()138 void RevocationList::on_delRev_clicked()
139 {
140 	QTreeWidgetItem *current = certList->currentItem();
141 	x509rev rev;
142 	int idx;
143 
144 	if (!current)
145 		return;
146 	idx = certList->indexOfTopLevelItem(current);
147 	certList->takeTopLevelItem(idx);
148 	rev.setSerial(a1int(current->text(Cserial)));
149 	idx = revList.indexOf(rev);
150         if (idx != -1)
151                 revList.takeAt(idx);
152 }
153 
on_editRev_clicked()154 void RevocationList::on_editRev_clicked()
155 {
156 	on_certList_itemDoubleClicked(certList->currentItem());
157 }
158 
on_certList_itemDoubleClicked(QTreeWidgetItem * current)159 void RevocationList::on_certList_itemDoubleClicked(QTreeWidgetItem *current)
160 {
161 	x509rev rev;
162 	int idx;
163 
164 	if (!current)
165 		return;
166 
167 	rev.setSerial(a1int(current->text(Cserial)));
168 	idx = revList.indexOf(rev);
169         if (idx == -1)
170 		return;
171 
172 	rev = revList[idx];
173 
174 	Revocation *revoke = new Revocation(QModelIndexList(), this);
175 	revoke->setRevocation(rev);
176         if (revoke->exec()) {
177 		a1time a1 = rev.getDate();
178 		rev = revoke->getRevocation();
179 		rev.setDate(a1);
180 		revList[idx] = rev;
181 		setup_revRevItem(current, rev, issuer);
182 	}
183 	delete revoke;
184 }
185 
Revocation(QModelIndexList indexes,QWidget * w)186 Revocation::Revocation(QModelIndexList indexes, QWidget *w) : QDialog(w ?: mainwin)
187 {
188 	setupUi(this);
189 	setWindowTitle(XCA_TITLE);
190 	mainwin->helpdlg->register_ctxhelp_button(this, "crlrevocation");
191 
192 	reason->addItems(x509rev::crlreasons());
193 	invalid->setNow();
194 
195 	if (indexes.size() > 1) {
196 		QList<a1int> serials;
197 		QStringList sl;
198 		serial->setText(QString("Batch revocation of %1 Certificates").
199 				arg(indexes.size()));
200 		foreach(QModelIndex idx, indexes) {
201 			pki_x509 *cert = db_base::fromIndex<pki_x509>(idx);
202 			if (cert)
203 				serials << cert->getSerial();
204 		}
205 		std::sort(serials.begin(), serials.end());
206 		foreach(a1int a, serials)
207 			sl << a;
208 		serial->setToolTip(sl.join("\n"));
209 		serial->setEnabled(false);
210 	} else if (indexes.size() == 1) {
211 		pki_x509 *cert = db_base::fromIndex<pki_x509>(indexes[0]);
212 		serial->setText(cert->getSerial());
213 		serial->setEnabled(false);
214 	} else {
215 		serial->setValidator(
216 			new QRegExpValidator(QRegExp("[A-Fa-f0-9]+"), serial));
217 	}
218 }
219 
getRevocation()220 x509rev Revocation::getRevocation()
221 {
222 	x509rev r;
223 
224 	r.setSerial(a1int(serial->text()));
225 	r.setInvalDate(invalid->getDate());
226 	r.setDate(a1time());
227 	r.setCrlNo(0);
228 	r.setReason(reason->currentText());
229 	return r;
230 }
231 
setRevocation(x509rev r)232 void Revocation::setRevocation(x509rev r)
233 {
234 	serial->setText(r.getSerial());
235 	invalid->setDate(r.getInvalDate());
236 	int i = reason->findText(r.getReason());
237 	if (i == -1)
238 		i = 0;
239 	reason->setCurrentIndex(i);
240 }
241