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