1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2009 - 2020 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 
9 #include "pki_key.h"
10 #include "pki_x509super.h"
11 #include "func.h"
12 #include "db.h"
13 #include "pkcs11.h"
14 #include "widgets/XcaWarning.h"
15 #include "widgets/ExportDialog.h"
16 
17 #include <openssl/rand.h>
18 #include <openssl/pem.h>
19 
20 #include "openssl_compat.h"
21 
22 builtin_curves builtinCurves;
23 
pki_key(const QString & name)24 pki_key::pki_key(const QString &name)
25         :pki_base(name)
26 {
27 	key = EVP_PKEY_new();
28 	key_size = 0;
29 	isPub = true;
30 	useCount = -1;
31 }
32 
pki_key(const pki_key * pk)33 pki_key::pki_key(const pki_key *pk)
34 	:pki_base(pk)
35 {
36 	if (pk->key) {
37 		QByteArray ba = i2d_bytearray(I2D_VOID(i2d_PUBKEY), pk->key);
38 		key = NULL;
39 		d2i(ba);
40 		sqlItemId = pk->sqlItemId;
41 	} else {
42 		key = EVP_PKEY_new();
43 	}
44 	key_size = pk->key_size;
45 	useCount = -1;
46 }
47 
~pki_key()48 pki_key::~pki_key()
49 {
50 	if (key)
51 		EVP_PKEY_free(key);
52 }
53 
autoIntName(const QString & file)54 void pki_key::autoIntName(const QString &file)
55 {
56 	pki_base::autoIntName(file);
57 	if (!getIntName().isEmpty())
58 		return;
59 	setIntName(QString("%1 %2%3").arg(length(), getTypeString(),
60 		isPubKey() ? QString(" ") + tr("Public key") : QString()));
61 }
62 
d2i(QByteArray & ba)63 void pki_key::d2i(QByteArray &ba)
64 {
65 	EVP_PKEY *k = (EVP_PKEY*)d2i_bytearray(D2I_VOID(d2i_PUBKEY), ba);
66         pki_openssl_error();
67 	if (k) {
68 		if (key)
69 			EVP_PKEY_free(key);
70 		key = k;
71 	}
72 }
73 
d2i_old(QByteArray & ba,int type)74 void pki_key::d2i_old(QByteArray &ba, int type)
75 {
76 	const unsigned char *p, *p1;
77 	p = p1 = (const unsigned char *)ba.constData();
78 	EVP_PKEY *k = d2i_PublicKey(type, NULL, &p1, ba.count());
79 
80         pki_openssl_error();
81 
82 	if (k) {
83 		if (key)
84 			EVP_PKEY_free(key);
85 		key = k;
86 	}
87         ba = ba.mid(p1-p);
88 }
89 
i2d() const90 QByteArray pki_key::i2d() const
91 {
92         return i2d_bytearray(I2D_VOID(i2d_PUBKEY), key);
93 }
94 
write_SSH2_ed25519_private(BIO * b,const EVP_PKEY * pkey,const EVP_CIPHER * enc) const95 void pki_key::write_SSH2_ed25519_private(BIO *b,
96 			 const EVP_PKEY *pkey, const EVP_CIPHER *enc) const
97 {
98 #ifndef OPENSSL_NO_EC
99 	static const char data0001[] = { 0, 0, 0, 1};
100 	char buf_nonce[8];
101 	QByteArray data, priv, pubfull;
102 	(void)enc;
103 
104 	pubfull = SSH2publicQByteArray(true);
105 	RAND_bytes((unsigned char*)buf_nonce, sizeof buf_nonce);
106 	priv.append(buf_nonce, sizeof buf_nonce);
107 	priv += pubfull;
108 	ssh_key_QBA2data(ed25519PrivKey(pkey) + ed25519PubKey(), &priv);
109 
110 	data = "openssh-key-v1";
111 	data.append('\0');
112 	ssh_key_QBA2data("none", &data); // enc-alg
113 	ssh_key_QBA2data("none", &data); // KDF name
114 	ssh_key_QBA2data("", &data); // KDF data
115 	data.append(data0001, sizeof data0001);
116 	ssh_key_QBA2data(pubfull, &data);
117 	ssh_key_QBA2data(priv, &data);
118 
119 	PEM_write_bio(b, PEM_STRING_OPENSSH_KEY, (char*)"",
120 		(unsigned char*)(data.data()), data.size());
121 	pki_openssl_error();
122 #endif
123 }
124 
pem(BioByteArray & b,int format)125 bool pki_key::pem(BioByteArray &b, int format)
126 {
127 	EVP_PKEY *pkey;
128 	QByteArray ba;
129 	int keytype;
130 
131 	switch (format) {
132 	case exportType::SSH2_public:
133 		b += SSH2publicQByteArray();
134 		break;
135 	case exportType::PEM_private:
136 	case exportType::SSH2_private:
137 		pkey = decryptKey();
138 		keytype = EVP_PKEY_id(pkey);
139 		switch (keytype) {
140 		case EVP_PKEY_RSA:
141 			PEM_write_bio_RSAPrivateKey(b,
142 				EVP_PKEY_get0_RSA(pkey),
143 				NULL, NULL, 0, NULL, NULL);
144 			break;
145 		case EVP_PKEY_DSA:
146 			PEM_write_bio_DSAPrivateKey(b,
147 				EVP_PKEY_get0_DSA(pkey),
148 				NULL, NULL, 0, NULL, NULL);
149 			break;
150 #ifndef OPENSSL_NO_EC
151 		case EVP_PKEY_EC:
152 			PEM_write_bio_ECPrivateKey(b,
153 				EVP_PKEY_get0_EC_KEY(pkey),
154 				NULL, NULL, 0, NULL, NULL);
155 			break;
156 #ifdef EVP_PKEY_ED25519
157 		case EVP_PKEY_ED25519:
158 			if (format == exportType::PEM_private)
159 				return false;
160 			write_SSH2_ed25519_private(b, pkey, NULL);
161 			break;
162 #endif
163 #endif
164 		}
165 		EVP_PKEY_free(pkey);
166 		break;
167 	case exportType::PKCS8:
168 		pkey = decryptKey();
169 		PEM_write_bio_PrivateKey(b, pkey, NULL, NULL, 0, NULL, NULL);
170 		EVP_PKEY_free(pkey);
171 		break;
172 	case exportType::PEM_key:
173 		PEM_write_bio_PUBKEY(b, key);
174 		break;
175 	default:
176 		return false;
177 	}
178 	return true;
179 }
180 
writeSSH2private(XFile & file,pem_password_cb * cb) const181 void pki_key::writeSSH2private(XFile &file, pem_password_cb *cb) const
182 {
183 	(void)cb;
184 //	pass_info p(XCA_TITLE, tr("Please enter the password protecting the SSH2 private key '%1'").arg(getIntName()));
185 
186 	EVP_PKEY *pkey = decryptKey();
187 	if (!pkey) {
188 		pki_openssl_error();
189 		return;
190 	}
191 	write_SSH2_ed25519_private(file.bio(), pkey, NULL);
192 }
193 
length() const194 QString pki_key::length() const
195 {
196 	bool dsa_unset = false;
197 
198 	if (EVP_PKEY_id(key) == EVP_PKEY_DSA) {
199 		const BIGNUM *p = NULL;
200 		DSA *dsa = EVP_PKEY_get0_DSA(key);
201 		if (dsa)
202 			DSA_get0_pqg(dsa, &p, NULL, NULL);
203 		dsa_unset = p == NULL;
204 	}
205 
206 	if (dsa_unset)
207 		return QString("???");
208 
209 	return QString("%1 bit").arg(EVP_PKEY_bits(key));
210 }
211 
212 /* getKeyTypeString() returns RSA
213  * getTypeString() returns RSA or "Token RSA" for tokens
214  */
getKeyTypeString() const215 QString pki_key::getKeyTypeString() const
216 {
217 	return keytype::byPKEY(key).name;
218 }
219 
getTypeString() const220 QString pki_key::getTypeString() const
221 {
222 	return getKeyTypeString();
223 }
224 
getMsg(msg_type msg) const225 QString pki_key::getMsg(msg_type msg) const
226 {
227 	/*
228 	 * We do not construct english sentences (just a little bit)
229 	 * from fragments to allow proper translations.
230 	 * The drawback are all the slightly different duplicated messages
231 	 *
232 	 * %1 will be replaced by "RSA", "DSA", "EC"
233 	 * %2 is the internal name of the key
234 	 */
235 	QString ktype = getTypeString();
236 	if (isPubKey()) {
237 		switch (msg) {
238 		case msg_import: return tr("Successfully imported the %1 public key '%2'").arg(ktype);
239 		case msg_delete: return tr("Delete the %1 public key '%2'?").arg(ktype);
240 		default: break;
241 		}
242 	} else {
243 		switch (msg) {
244 		case msg_import: return tr("Successfully imported the %1 private key '%2'").arg(ktype);
245 		case msg_delete: return tr("Delete the %1 private key '%2'?").arg(ktype);
246 		case msg_create: return tr("Successfully created the %1 private key '%2'").arg(ktype);
247 		default: break;
248 		}
249 	}
250 	if (msg == msg_delete_multi) {
251 		/* %1: Number of keys; %2: list of keynames */
252 		return tr("Delete the %1 keys: %2?");
253 	}
254 	return pki_base::getMsg(msg);
255 }
256 
comboText() const257 QString pki_key::comboText() const
258 {
259 	return QString("%1 (%2:%3%4)").arg(getIntName()).arg(getTypeString()).
260 		arg(length()).arg(isPubKey() ?
261 			QString(" ") + tr("Public key") : QString(""));
262 }
263 
isToken()264 bool pki_key::isToken()
265 {
266 	return false;
267 }
268 
isPrivKey() const269 bool pki_key::isPrivKey() const
270 {
271 	return !isPubKey();
272 }
273 
getUcount() const274 int pki_key::getUcount() const
275 {
276 	XSqlQuery q;
277 	if (useCount != -1)
278 		return useCount;
279 	int size = -1;
280 	SQL_PREPARE(q, "SELECT COUNT(*) FROM x509super WHERE pkey=?");
281 	q.bindValue(0, sqlItemId);
282 	q.exec();
283 	if (q.first())
284 		size = q.value(0).toInt();
285 	else
286 		qDebug("Failed to get key count for %s", CCHAR(getIntName()));
287 	XCA_SQLERROR(q.lastError());
288 	useCount = size;
289 	return size;
290 }
291 
getKeyType() const292 int pki_key::getKeyType() const
293 {
294 	return EVP_PKEY_id(key);
295 }
296 
modulus() const297 QString pki_key::modulus() const
298 {
299 	if (getKeyType() == EVP_PKEY_RSA) {
300 		const BIGNUM *n = NULL;
301 
302 		RSA *rsa = EVP_PKEY_get0_RSA(key);
303 		RSA_get0_key(rsa, &n, NULL, NULL);
304 		return BN2QString(n);
305 	}
306 	return QString();
307 }
308 
pubEx() const309 QString pki_key::pubEx() const
310 {
311 	if (getKeyType() == EVP_PKEY_RSA) {
312 		const BIGNUM *e = NULL;
313 		RSA *rsa = EVP_PKEY_get0_RSA(key);
314 		RSA_get0_key(rsa, NULL, &e, NULL);
315 		return BN2QString(e);
316 	}
317 	return QString();
318 }
319 
subprime() const320 QString pki_key::subprime() const
321 {
322 	if (getKeyType() == EVP_PKEY_DSA) {
323 		const BIGNUM *q = NULL;
324 		DSA *dsa = EVP_PKEY_get0_DSA(key);
325 		if (dsa)
326 			DSA_get0_pqg(dsa, NULL, &q, NULL);
327 		return BN2QString(q);
328 	}
329 	return QString();
330 }
331 
pubkey() const332 QString pki_key::pubkey() const
333 {
334 	if (getKeyType() == EVP_PKEY_DSA) {
335 		const BIGNUM *pubkey = NULL;
336 		DSA *dsa = EVP_PKEY_get0_DSA(key);
337 		if (dsa)
338 			DSA_get0_key(dsa, &pubkey, NULL);
339 		return BN2QString(pubkey);
340 	}
341 	return QString();
342 }
343 #ifndef OPENSSL_NO_EC
ecParamNid() const344 int pki_key::ecParamNid() const
345 {
346 	const EC_KEY *ec;
347 
348 	if (getKeyType() != EVP_PKEY_EC)
349 		return NID_undef;
350 	ec = EVP_PKEY_get0_EC_KEY(key);
351 	return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
352 }
353 
ecPubKeyBN() const354 BIGNUM *pki_key::ecPubKeyBN() const
355 {
356 	if (getKeyType() != EVP_PKEY_EC)
357 		return NULL;
358 
359 	const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key);
360 	return EC_POINT_point2bn(EC_KEY_get0_group(ec),
361 				 EC_KEY_get0_public_key(ec),
362 				 EC_KEY_get_conv_form(ec), NULL, NULL);
363 }
364 
ecPubKey() const365 QString pki_key::ecPubKey() const
366 {
367 	QString pub;
368 	BIGNUM *pub_key = ecPubKeyBN();
369 	if (pub_key) {
370 		pub = BN2QString(pub_key);
371 		BN_free(pub_key);
372 	}
373 	return pub;
374 }
375 
376 #ifdef EVP_PKEY_ED25519
ed25519Key(int (* EVP_PKEY_get_raw)(const EVP_PKEY *,unsigned char *,size_t *),const EVP_PKEY * pkey)377 static QByteArray ed25519Key(int(*EVP_PKEY_get_raw)
378 			(const EVP_PKEY*, unsigned char *, size_t *),
379 			const EVP_PKEY *pkey)
380 {
381 	unsigned char k[ED25519_KEYLEN];
382 	size_t len = sizeof k;
383 
384 	if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519 &&
385 	    EVP_PKEY_get_raw(pkey, k, &len))
386 		return QByteArray((char*)k, len);
387 	return QByteArray();
388 }
389 
ed25519PubKey() const390 QByteArray pki_key::ed25519PubKey() const
391 {
392 	return ed25519Key(EVP_PKEY_get_raw_public_key, key);
393 }
394 
ed25519PrivKey(const EVP_PKEY * pkey) const395 QByteArray pki_key::ed25519PrivKey(const EVP_PKEY *pkey) const
396 {
397 	return ed25519Key(EVP_PKEY_get_raw_private_key, pkey);
398 }
399 #else
400 
ed25519PubKey() const401 QByteArray pki_key::ed25519PubKey() const
402 {
403 	return QByteArray();
404 }
405 
ed25519PrivKey(const EVP_PKEY *) const406 QByteArray pki_key::ed25519PrivKey(const EVP_PKEY *) const
407 {
408 	return QByteArray();
409 }
410 
411 #endif
412 #endif
413 
possibleHashNids()414 QList<int> pki_key::possibleHashNids()
415 {
416 	QList<int> nids;
417 
418 	switch (EVP_PKEY_type(getKeyType())) {
419 		case EVP_PKEY_RSA:
420 			nids << NID_md5 << NID_sha1 << NID_sha224 << NID_sha256 <<
421 				NID_sha384 << NID_sha512 << NID_ripemd160;
422 			break;
423 		case EVP_PKEY_DSA:
424 			nids << NID_sha1;
425 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
426 			nids << NID_sha256;
427 #endif
428 			break;
429 		case EVP_PKEY_EC:
430 			nids << NID_sha1;
431 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
432 			nids << NID_sha224 << NID_sha256 << NID_sha384 << NID_sha512;
433 #endif
434 			break;
435 	}
436 	return nids;
437 };
438 
compare(const pki_base * ref) const439 bool pki_key::compare(const pki_base *ref) const
440 {
441 	const pki_key *kref = (pki_key *)ref;
442 
443 	if (kref->getKeyType() != getKeyType())
444 		return false;
445 	if (!kref || !kref->key || !key)
446 		return false;
447 
448 	int r = EVP_PKEY_cmp(key, kref->key);
449 	pki_openssl_error();
450 	return r == 1;
451 }
452 
writePublic(XFile & file,bool pem) const453 void pki_key::writePublic(XFile &file, bool pem) const
454 {
455 	if (pem) {
456 		PEM_file_comment(file);
457 		PEM_write_PUBKEY(file.fp(), key);
458 	} else {
459 		i2d_PUBKEY_fp(file.fp(), key);
460 	}
461 	pki_openssl_error();
462 }
463 
BNoneLine(BIGNUM * bn) const464 QString pki_key::BNoneLine(BIGNUM *bn) const
465 {
466 	QString x;
467 	if (bn) {
468 		char *hex = BN_bn2hex(bn);
469 		x = hex;
470 		OPENSSL_free(hex);
471 		pki_openssl_error();
472 	}
473 	return x;
474 }
475 
BN2QString(const BIGNUM * bn) const476 QString pki_key::BN2QString(const BIGNUM *bn) const
477 {
478 	if (bn == NULL)
479 		return "--";
480 	QString x="";
481 	char zs[10];
482 	int j, size = BN_num_bytes(bn);
483 	unsigned char *buf = (unsigned char *)OPENSSL_malloc(size);
484 	check_oom(buf);
485 	BN_bn2bin(bn, buf);
486 	for (j = 0; j< size; j++) {
487 		sprintf(zs, "%02X%c",buf[j], ((j+1)%16 == 0) ? '\n' :
488 				j<size-1 ? ':' : ' ');
489 		x += zs;
490 	}
491 	OPENSSL_free(buf);
492 	pki_openssl_error();
493 	return x;
494 }
495 
column_data(const dbheader * hd) const496 QVariant pki_key::column_data(const dbheader *hd) const
497 {
498 	QStringList sl;
499 	sl << tr("Common") << tr("Private") << tr("Bogus") << tr("PIN");
500 	switch (hd->id) {
501 		case HD_key_type:
502 			return QVariant(getTypeString());
503 		case HD_key_size:
504 			return QVariant(length());
505 		case HD_key_use:
506 			return QVariant(getUcount());
507 		case HD_key_passwd:
508 			if (isPubKey())
509 				return QVariant(tr("No password"));
510 			if (ownPass<0 || ownPass>3)
511 				return QVariant("Holla die Waldfee");
512 			return QVariant(sl[ownPass]);
513 		case HD_key_curve:
514 			QString r;
515 #ifndef OPENSSL_NO_EC
516 			if (getKeyType() == EVP_PKEY_EC)
517 				r = OBJ_nid2sn(ecParamNid());
518 #endif
519 			return QVariant(r);
520 	}
521 	return pki_base::column_data(hd);
522 }
523 
insertSqlData()524 QSqlError pki_key::insertSqlData()
525 {
526 	unsigned myhash = hash();
527 	XSqlQuery q;
528 	QList<pki_x509super*> list;
529 
530 	SQL_PREPARE(q, "SELECT item FROM x509super WHERE key_hash=? AND "
531 			"pkey IS NULL");
532 	q.bindValue(0, myhash);
533 	q.exec();
534 	if (q.lastError().isValid())
535 		return q.lastError();
536 
537 	while (q.next()) {
538 		pki_x509super *x;
539 		x = Store.lookupPki<pki_x509super>(q.value(0));
540 		if (!x) {
541 			qDebug("X509 Super class with id %d not found",
542 				q.value(0).toInt());
543 			continue;
544 		}
545 		if (x->compareRefKey(this)) {
546 			x->setRefKey(this);
547 			list << x;
548 		}
549 	}
550 	q.finish();
551 
552 	SQL_PREPARE(q, "UPDATE x509super SET pkey=? WHERE item=?");
553 	q.bindValue(0, sqlItemId);
554 	foreach(pki_x509super* x, list) {
555 		q.bindValue(1, x->getSqlItemId());
556 		q.exec();
557 		AffectedItems(x->getSqlItemId());
558 		if (q.lastError().isValid())
559 			return q.lastError();
560 	}
561 	q.finish();
562 
563 	SQL_PREPARE(q, "INSERT INTO public_keys (item, type, hash, len, \"public\") "
564 		  "VALUES (?, ?, ?, ?, ?)");
565 	q.bindValue(0, sqlItemId);
566 	q.bindValue(1, getKeyTypeString().left(4));
567 	q.bindValue(2, myhash);
568 	q.bindValue(3, EVP_PKEY_bits(key));
569 	q.bindValue(4, i2d_b64());
570 	q.exec();
571 	return q.lastError();
572 }
573 
restoreSql(const QSqlRecord & rec)574 void pki_key::restoreSql(const QSqlRecord &rec)
575 {
576 	pki_base::restoreSql(rec);
577 	QByteArray ba = QByteArray::fromBase64(
578 			rec.value(VIEW_public_keys_public).toByteArray());
579 	d2i(ba);
580 	key_size = rec.value(VIEW_public_keys_len).toInt();
581 }
582 
deleteSqlData()583 QSqlError pki_key::deleteSqlData()
584 {
585 	XSqlQuery q;
586 	QSqlError e;
587 
588 	SQL_PREPARE(q, "DELETE FROM public_keys WHERE item=?");
589 	q.bindValue(0, sqlItemId);
590 	q.exec();
591 	e = q.lastError();
592 	if (e.isValid())
593 		return e;
594 	SQL_PREPARE(q, "UPDATE x509super SET pkey=NULL WHERE pkey=?");
595 	q.bindValue(0, sqlItemId);
596 	AffectedItems(sqlItemId);
597 	q.exec();
598 	return q.lastError();
599 }
600 
ssh_key_check_chunk(QByteArray * ba,const char * expect) const601 void pki_key::ssh_key_check_chunk(QByteArray *ba, const char *expect) const
602 {
603 	QByteArray chunk = ssh_key_next_chunk(ba);
604 
605 	if (chunk != expect)
606 		throw errorEx(tr("Unexpected SSH2 content: '%1'")
607 				.arg(QString(chunk)));
608 }
609 
ssh_key_data2bn(QByteArray * ba) const610 BIGNUM *pki_key::ssh_key_data2bn(QByteArray *ba) const
611 {
612 	QByteArray chunk = ssh_key_next_chunk(ba);
613 	BIGNUM *bn = BN_bin2bn((const unsigned char *)chunk.constData(),
614 				chunk.size(), NULL);
615 	check_oom(bn);
616 	return bn;
617 }
618 
ssh_key_next_chunk(QByteArray * ba) const619 QByteArray pki_key::ssh_key_next_chunk(QByteArray *ba) const
620 {
621 	QByteArray chunk;
622 	const char *d;
623 	int len;
624 
625 	if (!ba || ba->size() < 4)
626 		throw errorEx(tr("Invalid SSH2 public key"));
627 
628 	d = ba->constData();
629 	len = (d[0] << 24) + (d[1] << 16) + (d[2] << 8) + d[3];
630 
631 	if (ba->size() < len + 4)
632 		throw errorEx(tr("Invalid SSH2 public key"));
633 	chunk = ba->mid(4, len);
634 	ba->remove(0, len +4);
635 	return chunk;
636 }
637 
load_ssh2_key(XFile & file)638 EVP_PKEY *pki_key::load_ssh2_key(XFile &file)
639 {
640 	/* See RFC 4253 Section 6.6 */
641 	QByteArray ba;
642 	QStringList sl;
643 	EVP_PKEY *pk = NULL;
644 
645 	ba = file.read(4096);
646 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
647 	sl = QString(ba).split(" ", Qt::SkipEmptyParts);
648 #else
649 	sl = QString(ba).split(" ", QString::SkipEmptyParts);
650 #endif
651 	if (sl.size() < 2)
652 		return NULL;
653 
654 	ba = QByteArray::fromBase64(sl[1].toLatin1());
655 	if (sl[0].startsWith("ssh-rsa")) {
656 		ssh_key_check_chunk(&ba, "ssh-rsa");
657 
658 		BIGNUM *e = ssh_key_data2bn(&ba);
659 		BIGNUM *n = ssh_key_data2bn(&ba);
660 
661 		RSA *rsa = RSA_new();
662 		check_oom(rsa);
663 		RSA_set0_key(rsa, n, e, NULL);
664 		pk = EVP_PKEY_new();
665 		check_oom(pk);
666 		EVP_PKEY_assign_RSA(pk, rsa);
667 	} else if (sl[0].startsWith("ssh-dss")) {
668 		ssh_key_check_chunk(&ba, "ssh-dss");
669 		BIGNUM *p = ssh_key_data2bn(&ba);
670 		BIGNUM *q = ssh_key_data2bn(&ba);
671 		BIGNUM *g = ssh_key_data2bn(&ba);
672 		BIGNUM *pubkey = ssh_key_data2bn(&ba);
673 		DSA *dsa = DSA_new();
674 		check_oom(dsa);
675 
676 		DSA_set0_pqg(dsa, p, q, g);
677 		DSA_set0_key(dsa, pubkey, NULL);
678 
679 		pk = EVP_PKEY_new();
680 		check_oom(pk);
681 		EVP_PKEY_assign_DSA(pk, dsa);
682 #ifndef OPENSSL_NO_EC
683 	} else if (sl[0].startsWith("ecdsa-sha2-nistp256")) {
684 		EC_KEY *ec;
685 
686 		/* Skip "ecdsa-sha2..." */
687 		ssh_key_check_chunk(&ba, "ecdsa-sha2-nistp256");
688 		ssh_key_check_chunk(&ba, "nistp256");
689 		BIGNUM *bn = ssh_key_data2bn(&ba);
690 
691 		ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
692 		check_oom(ec);
693 		EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
694 		EC_KEY_set_public_key(ec, EC_POINT_bn2point(
695 					EC_KEY_get0_group(ec), bn, NULL, NULL));
696 		BN_free(bn);
697 		pki_openssl_error();
698 
699 		pk = EVP_PKEY_new();
700 		check_oom(pk);
701 		EVP_PKEY_assign_EC_KEY(pk, ec);
702 #ifdef EVP_PKEY_ED25519
703 	} else if (sl[0].startsWith("ssh-ed25519")) {
704 		ssh_key_check_chunk(&ba, "ssh-ed25519");
705 		QByteArray pub = ssh_key_next_chunk(&ba);
706 		pk = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
707 			(const unsigned char *)pub.constData(), pub.count());
708 		pki_openssl_error();
709 #endif
710 #endif
711 	} else {
712 		throw errorEx(tr("Unexpected SSH2 content: '%1'").arg(sl[0]));
713 	}
714 	if (sl.size() > 2 && pk)
715 		setComment(sl[2].section('\n', 0, 0));
716 
717 	return pk;
718 }
719 
ssh_key_QBA2data(const QByteArray & ba,QByteArray * data) const720 void pki_key::ssh_key_QBA2data(const QByteArray &ba, QByteArray *data) const
721 {
722 	int size = ba.size();
723 	unsigned char p[4];
724 
725 	p[0] = (size >> 24) & 0xff;
726 	p[1] = (size >> 16) & 0xff;
727 	p[2] = (size >>  8) & 0xff;
728 	p[3] = size & 0xff;
729 	data->append((char*)p, sizeof p);
730 	data->append(ba);
731 }
732 
ssh_key_bn2data(const BIGNUM * bn,QByteArray * data) const733 void pki_key::ssh_key_bn2data(const BIGNUM *bn, QByteArray *data) const
734 {
735 	QByteArray big;
736 	big.resize(BN_num_bytes(bn));
737 	BN_bn2bin(bn, (unsigned char *)big.data());
738 	pki_openssl_error();
739 	if ((unsigned char)big[0] >= 0x80)
740 		big.prepend('\0');
741 	ssh_key_QBA2data(big, data);
742 }
743 
SSH2_compatible() const744 bool pki_key::SSH2_compatible() const
745 {
746 	switch (getKeyType()) {
747 #ifndef OPENSSL_NO_EC
748 	case EVP_PKEY_EC:
749 		return ecParamNid() == NID_X9_62_prime256v1;
750 #ifdef EVP_PKEY_ED25519
751 	case EVP_PKEY_ED25519:
752 #endif
753 #endif
754 	case EVP_PKEY_RSA:
755 	case EVP_PKEY_DSA:
756 		return true;
757 	}
758 	return false;
759 }
760 
SSH2publicQByteArray(bool raw) const761 QByteArray pki_key::SSH2publicQByteArray(bool raw) const
762 {
763 	QByteArray txt, data;
764 	switch (getKeyType()) {
765 	case EVP_PKEY_RSA:
766 		txt = "ssh-rsa";
767 		ssh_key_QBA2data(txt, &data);
768 		{
769 			RSA *rsa = EVP_PKEY_get0_RSA(key);
770 			const BIGNUM *n, *e;
771 			RSA_get0_key(rsa, &n, &e, NULL);
772 			ssh_key_bn2data(e, &data);
773 			ssh_key_bn2data(n, &data);
774 		}
775 		break;
776 	case EVP_PKEY_DSA:
777 		txt = "ssh-dss";
778 		ssh_key_QBA2data(txt, &data);
779 		{
780 			DSA *dsa = EVP_PKEY_get0_DSA(key);
781 			const BIGNUM *p, *q, *g, *pubkey;
782 			DSA_get0_pqg(dsa, &p, &q, &g);
783 			DSA_get0_key(dsa, &pubkey, NULL);
784 			ssh_key_bn2data(p, &data);
785 			ssh_key_bn2data(q, &data);
786 			ssh_key_bn2data(g, &data);
787 			ssh_key_bn2data(pubkey, &data);
788 		}
789 		break;
790 #ifndef OPENSSL_NO_EC
791 	case EVP_PKEY_EC:
792 		if (ecParamNid() != NID_X9_62_prime256v1)
793 			return QByteArray();
794 
795 		txt = "ecdsa-sha2-nistp256";
796 		ssh_key_QBA2data(txt, &data);
797 		ssh_key_QBA2data("nistp256", &data);
798 		{
799 			BIGNUM *bn = ecPubKeyBN();
800 			ssh_key_bn2data(bn, &data);
801 			BN_free(bn);
802 		}
803 		pki_openssl_error();
804 		break;
805 #ifdef EVP_PKEY_ED25519
806 	case EVP_PKEY_ED25519:
807 		txt = "ssh-ed25519";
808 		ssh_key_QBA2data(txt, &data);
809 		ssh_key_QBA2data(ed25519PubKey(), &data);
810 		break;
811 #endif
812 #endif
813 	default:
814 		return QByteArray();
815 	}
816 	if (raw)
817 		return data;
818 
819 	txt += " " + data.toBase64();
820 	QString comm = comment.section('\n', 0, 0).simplified();
821 	if (comm.size() > 0)
822 		txt += " " + comm.toUtf8();
823 	return txt + "\n";
824 }
825 
writeSSH2public(XFile & file) const826 void pki_key::writeSSH2public(XFile &file) const
827 {
828 	QByteArray txt = SSH2publicQByteArray();
829 	if (file.write(txt) != txt.size())
830 		throw errorEx(tr("Failed writing to %1").arg(file.fileName()));
831 }
832 
verify(EVP_PKEY * pkey) const833 bool pki_key::verify(EVP_PKEY *pkey) const
834 {
835 	bool verify = true;
836 	const BIGNUM *a = NULL;
837 	const BIGNUM *b = NULL;
838 	const BIGNUM *c = NULL;
839 
840 	switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
841 	case EVP_PKEY_RSA:
842 		RSA_get0_key(EVP_PKEY_get0_RSA(pkey), &a, &b, NULL);
843 		verify = a && b;
844 		break;
845 	case EVP_PKEY_DSA:
846 		DSA_get0_pqg(EVP_PKEY_get0_DSA(pkey), &a, &b, &c);
847 		verify = a && b && c;
848 		break;
849 #ifndef OPENSSL_NO_EC
850 	case EVP_PKEY_EC:
851 		verify = EC_KEY_check_key(EVP_PKEY_get0_EC_KEY(pkey)) == 1;
852 		break;
853 #ifdef EVP_PKEY_ED25519
854 	case EVP_PKEY_ED25519: {
855 		size_t len;
856 		verify = EVP_PKEY_get_raw_private_key(pkey, NULL, &len) == 1 &&
857 				len == ED25519_KEYLEN;
858 		break;
859 	}
860 #endif
861 #endif
862 	default:
863 		verify = false;
864 	}
865 	if (verify)
866 		verify = verify_priv(pkey);
867 	pki_openssl_error();
868 	return verify;
869 }
870 
verify_priv(EVP_PKEY *) const871 bool pki_key::verify_priv(EVP_PKEY *) const
872 {
873 	return true;
874 }
875 
fingerprint(const QString & format) const876 QString pki_key::fingerprint(const QString &format) const
877 {
878 	const EVP_MD *md;
879 	QByteArray data;
880 	QStringList sl = format.toLower().split(" ");
881 
882 	if (sl.size() < 2)
883 		return QString("Invalid format: %1").arg(format);
884 	if (sl[0] == "ssh")
885 		data = SSH2publicQByteArray(true);
886 	else if (sl[0] == "x509")
887 		data = X509_PUBKEY_public_key();
888 	else if (sl[0] == "der")
889 		data = i2d_bytearray(I2D_VOID(i2d_PUBKEY), key);
890 	else
891 		return QString("Invalid format: %1").arg(sl[0]);
892 
893 	md = EVP_get_digestbyname(CCHAR(sl[1]));
894 	if (!md)
895 		return QString("Invalid hash: %1").arg(sl[1]);
896 
897 	if (sl.size() > 2 && sl[2] == "b64") {
898 		QString s(Digest(data, md).toBase64());
899 		s.chop(1);
900 		return s;
901 	}
902 	return ::fingerprint(data, md);
903 }
904 
X509_PUBKEY_public_key() const905 QByteArray pki_key::X509_PUBKEY_public_key() const
906 {
907 	X509_PUBKEY *pk = NULL;
908 	const unsigned char *p;
909 	int len;
910 
911 	X509_PUBKEY_set(&pk, key);
912 #if OPENSSL_VERSION_NUMBER < 0x10000000L
913 	p = pk->public_key->data;
914 	len = pk->public_key->length;
915 #else
916 	X509_PUBKEY_get0_param(NULL, &p, &len, NULL, pk);
917 #endif
918 
919 	QByteArray data((const char*)p, len);
920 	X509_PUBKEY_free(pk);
921 	return data;
922 }
923 
PEM_file_comment(XFile & file) const924 void pki_key::PEM_file_comment(XFile &file) const
925 {
926 	if (!pem_comment)
927 		return;
928 	pki_base::PEM_file_comment(file);
929 	file.write(QString("%1 %2\n").arg(length(), getTypeString())
930 			.toUtf8());
931 }
932 
collect_properties(QMap<QString,QString> & prp) const933 void pki_key::collect_properties(QMap<QString, QString> &prp) const
934 {
935 	QStringList sl;
936 	sl << getTypeString() << length();
937 	if (isPubKey())
938 		sl << tr("Public key");
939 #ifndef OPENSSL_NO_EC
940 	if (getKeyType() == EVP_PKEY_EC)
941 		sl << QString(OBJ_nid2ln(ecParamNid()));
942 #endif
943 	prp["Key"] = sl.join(" ");
944 	pki_base::collect_properties(prp);
945 }
946 
print(BioByteArray & bba,enum print_opt opt) const947 void pki_key::print(BioByteArray &bba, enum print_opt opt) const
948 {
949 	pki_base::print(bba, opt);
950 	switch (opt) {
951 	case print_openssl_txt:
952 #if OPENSSL_VERSION_NUMBER < 0x10000000L
953 		bba += "Not supported\n";
954 #else
955 		EVP_PKEY_print_public(bba, key, 0, NULL);
956 #endif
957 		break;
958 	case print_pem:
959 		PEM_write_bio_PUBKEY(bba, key);
960 		break;
961 	case print_coloured:
962 		break;
963 	}
964 }
965