1 | /* |
2 | * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com> |
3 | * Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | * 02110-1301 USA |
19 | * |
20 | */ |
21 | |
22 | #include "qca_securemessage.h" |
23 | |
24 | #include "qca_safeobj.h" |
25 | #include "qca_safetimer.h" |
26 | #include "qcaprovider.h" |
27 | |
28 | namespace QCA { |
29 | |
30 | Provider::Context *getContext(const QString &type, const QString &provider); |
31 | |
32 | //---------------------------------------------------------------------------- |
33 | // SecureMessageKey |
34 | //---------------------------------------------------------------------------- |
35 | class SecureMessageKey::Private : public QSharedData |
36 | { |
37 | public: |
38 | SecureMessageKey::Type type; |
39 | PGPKey pgp_pub, pgp_sec; |
40 | CertificateChain cert_pub; |
41 | PrivateKey cert_sec; |
42 | |
43 | Private() |
44 | { |
45 | type = SecureMessageKey::None; |
46 | } |
47 | |
48 | // set the proper type, and reset the opposite data structures if needed |
49 | void ensureType(SecureMessageKey::Type t) |
50 | { |
51 | // if we were non-null and changed, we may need to reset some things |
52 | if (type != SecureMessageKey::None && t != type) { |
53 | if (type == SecureMessageKey::X509) { |
54 | cert_pub = CertificateChain(); |
55 | cert_sec = PrivateKey(); |
56 | } else if (type == SecureMessageKey::PGP) { |
57 | pgp_pub = PGPKey(); |
58 | pgp_sec = PGPKey(); |
59 | } |
60 | } |
61 | type = t; |
62 | } |
63 | }; |
64 | |
65 | SecureMessageKey::SecureMessageKey() |
66 | : d(new Private) |
67 | { |
68 | } |
69 | |
70 | SecureMessageKey::SecureMessageKey(const SecureMessageKey &from) |
71 | : d(from.d) |
72 | { |
73 | } |
74 | |
75 | SecureMessageKey::~SecureMessageKey() |
76 | { |
77 | } |
78 | |
79 | SecureMessageKey &SecureMessageKey::operator=(const SecureMessageKey &from) |
80 | { |
81 | d = from.d; |
82 | return *this; |
83 | } |
84 | |
85 | bool SecureMessageKey::isNull() const |
86 | { |
87 | return (d->type == None); |
88 | } |
89 | |
90 | SecureMessageKey::Type SecureMessageKey::type() const |
91 | { |
92 | return d->type; |
93 | } |
94 | |
95 | PGPKey SecureMessageKey::pgpPublicKey() const |
96 | { |
97 | return d->pgp_pub; |
98 | } |
99 | |
100 | PGPKey SecureMessageKey::pgpSecretKey() const |
101 | { |
102 | return d->pgp_sec; |
103 | } |
104 | |
105 | void SecureMessageKey::setPGPPublicKey(const PGPKey &pub) |
106 | { |
107 | d->ensureType(t: SecureMessageKey::PGP); |
108 | d->pgp_pub = pub; |
109 | } |
110 | |
111 | void SecureMessageKey::setPGPSecretKey(const PGPKey &sec) |
112 | { |
113 | d->ensureType(t: SecureMessageKey::PGP); |
114 | Q_ASSERT(sec.isSecret()); |
115 | d->pgp_sec = sec; |
116 | } |
117 | |
118 | CertificateChain SecureMessageKey::x509CertificateChain() const |
119 | { |
120 | return d->cert_pub; |
121 | } |
122 | |
123 | PrivateKey SecureMessageKey::x509PrivateKey() const |
124 | { |
125 | return d->cert_sec; |
126 | } |
127 | |
128 | void SecureMessageKey::setX509CertificateChain(const CertificateChain &c) |
129 | { |
130 | d->ensureType(t: SecureMessageKey::X509); |
131 | d->cert_pub = c; |
132 | } |
133 | |
134 | void SecureMessageKey::setX509PrivateKey(const PrivateKey &k) |
135 | { |
136 | d->ensureType(t: SecureMessageKey::X509); |
137 | d->cert_sec = k; |
138 | } |
139 | |
140 | void SecureMessageKey::setX509KeyBundle(const KeyBundle &kb) |
141 | { |
142 | setX509CertificateChain(kb.certificateChain()); |
143 | setX509PrivateKey(kb.privateKey()); |
144 | } |
145 | |
146 | bool SecureMessageKey::havePrivate() const |
147 | { |
148 | if (d->type == SecureMessageKey::PGP && !d->pgp_sec.isNull()) |
149 | return true; |
150 | else if (d->type == SecureMessageKey::X509 && !d->cert_sec.isNull()) |
151 | return true; |
152 | return false; |
153 | } |
154 | |
155 | QString SecureMessageKey::name() const |
156 | { |
157 | if (d->type == SecureMessageKey::PGP && !d->pgp_pub.isNull()) |
158 | return d->pgp_pub.primaryUserId(); |
159 | else if (d->type == SecureMessageKey::X509 && !d->cert_pub.isEmpty()) |
160 | return d->cert_pub.primary().commonName(); |
161 | else |
162 | return QString(); |
163 | } |
164 | |
165 | //---------------------------------------------------------------------------- |
166 | // SecureMessageSignature |
167 | //---------------------------------------------------------------------------- |
168 | class SecureMessageSignature::Private : public QSharedData |
169 | { |
170 | public: |
171 | SecureMessageSignature::IdentityResult r; |
172 | Validity v; |
173 | SecureMessageKey key; |
174 | QDateTime ts; |
175 | |
176 | Private() |
177 | { |
178 | r = SecureMessageSignature::NoKey; |
179 | v = ErrorValidityUnknown; |
180 | } |
181 | }; |
182 | |
183 | SecureMessageSignature::SecureMessageSignature() |
184 | : d(new Private) |
185 | { |
186 | } |
187 | |
188 | SecureMessageSignature::SecureMessageSignature(IdentityResult r, |
189 | Validity v, |
190 | const SecureMessageKey &key, |
191 | const QDateTime &ts) |
192 | : d(new Private) |
193 | { |
194 | d->r = r; |
195 | d->v = v; |
196 | d->key = key; |
197 | d->ts = ts; |
198 | } |
199 | |
200 | SecureMessageSignature::SecureMessageSignature(const SecureMessageSignature &from) |
201 | : d(from.d) |
202 | { |
203 | } |
204 | |
205 | SecureMessageSignature::~SecureMessageSignature() |
206 | { |
207 | } |
208 | |
209 | SecureMessageSignature &SecureMessageSignature::operator=(const SecureMessageSignature &from) |
210 | { |
211 | d = from.d; |
212 | return *this; |
213 | } |
214 | |
215 | SecureMessageSignature::IdentityResult SecureMessageSignature::identityResult() const |
216 | { |
217 | return d->r; |
218 | } |
219 | |
220 | Validity SecureMessageSignature::keyValidity() const |
221 | { |
222 | return d->v; |
223 | } |
224 | |
225 | SecureMessageKey SecureMessageSignature::key() const |
226 | { |
227 | return d->key; |
228 | } |
229 | |
230 | QDateTime SecureMessageSignature::timestamp() const |
231 | { |
232 | return d->ts; |
233 | } |
234 | |
235 | //---------------------------------------------------------------------------- |
236 | // SecureMessage |
237 | //---------------------------------------------------------------------------- |
238 | enum ResetMode |
239 | { |
240 | ResetSession = 0, |
241 | ResetSessionAndData = 1, |
242 | ResetAll = 2 |
243 | }; |
244 | |
245 | class SecureMessage::Private : public QObject |
246 | { |
247 | Q_OBJECT |
248 | public: |
249 | SecureMessage *q; |
250 | MessageContext *c; |
251 | SecureMessageSystem *system; |
252 | |
253 | bool bundleSigner, smime; |
254 | SecureMessage::Format format; |
255 | SecureMessageKeyList to; |
256 | SecureMessageKeyList from; |
257 | |
258 | QByteArray in; |
259 | bool success; |
260 | SecureMessage::Error errorCode; |
261 | QByteArray detachedSig; |
262 | QString hashName; |
263 | SecureMessageSignatureList signers; |
264 | QString dtext; |
265 | |
266 | QList<int> bytesWrittenArgs; |
267 | SafeTimer readyReadTrigger, bytesWrittenTrigger, finishedTrigger; |
268 | |
269 | Private(SecureMessage *_q) |
270 | : readyReadTrigger(this) |
271 | , bytesWrittenTrigger(this) |
272 | , finishedTrigger(this) |
273 | { |
274 | q = _q; |
275 | c = nullptr; |
276 | system = nullptr; |
277 | |
278 | readyReadTrigger.setSingleShot(true); |
279 | bytesWrittenTrigger.setSingleShot(true); |
280 | finishedTrigger.setSingleShot(true); |
281 | connect(sender: &readyReadTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::t_readyRead); |
282 | connect(sender: &bytesWrittenTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::t_bytesWritten); |
283 | connect(sender: &finishedTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::t_finished); |
284 | |
285 | reset(mode: ResetAll); |
286 | } |
287 | |
288 | void init() |
289 | { |
290 | connect(sender: c, signal: &MessageContext::updated, context: this, slot: &Private::updated); |
291 | } |
292 | |
293 | void reset(ResetMode mode) |
294 | { |
295 | if (c) |
296 | c->reset(); |
297 | |
298 | bytesWrittenArgs.clear(); |
299 | readyReadTrigger.stop(); |
300 | bytesWrittenTrigger.stop(); |
301 | finishedTrigger.stop(); |
302 | |
303 | if (mode >= ResetSessionAndData) { |
304 | in.clear(); |
305 | success = false; |
306 | errorCode = SecureMessage::ErrorUnknown; |
307 | detachedSig.clear(); |
308 | hashName = QString(); |
309 | signers.clear(); |
310 | } |
311 | |
312 | if (mode >= ResetAll) { |
313 | bundleSigner = true; |
314 | format = SecureMessage::Binary; |
315 | to.clear(); |
316 | from.clear(); |
317 | } |
318 | } |
319 | |
320 | public Q_SLOTS: |
321 | void updated() |
322 | { |
323 | bool sig_read = false; |
324 | bool sig_written = false; |
325 | bool sig_done = false; |
326 | int written = 0; |
327 | { |
328 | const QByteArray a = c->read(); |
329 | if (!a.isEmpty()) { |
330 | sig_read = true; |
331 | in.append(a); |
332 | } |
333 | |
334 | const int x = c->written(); |
335 | if (x > 0) { |
336 | sig_written = true; |
337 | written = x; |
338 | } |
339 | } |
340 | |
341 | if (c->finished()) { |
342 | sig_done = true; |
343 | |
344 | success = c->success(); |
345 | errorCode = c->errorCode(); |
346 | dtext = c->diagnosticText(); |
347 | if (success) { |
348 | detachedSig = c->signature(); |
349 | hashName = c->hashName(); |
350 | signers = c->signers(); |
351 | } |
352 | reset(mode: ResetSession); |
353 | } |
354 | |
355 | if (sig_read) |
356 | readyReadTrigger.start(); |
357 | if (sig_written) { |
358 | bytesWrittenArgs += written; |
359 | bytesWrittenTrigger.start(); |
360 | } |
361 | if (sig_done) |
362 | finishedTrigger.start(); |
363 | } |
364 | |
365 | void t_readyRead() |
366 | { |
367 | emit q->readyRead(); |
368 | } |
369 | |
370 | void t_bytesWritten() |
371 | { |
372 | emit q->bytesWritten(bytes: bytesWrittenArgs.takeFirst()); |
373 | } |
374 | |
375 | void t_finished() |
376 | { |
377 | emit q->finished(); |
378 | } |
379 | }; |
380 | |
381 | SecureMessage::SecureMessage(SecureMessageSystem *system) |
382 | { |
383 | d = new Private(this); |
384 | d->system = system; |
385 | d->c = static_cast<SMSContext *>(d->system->context())->createMessage(); |
386 | change(c: d->c); |
387 | d->init(); |
388 | } |
389 | |
390 | SecureMessage::~SecureMessage() |
391 | { |
392 | delete d; |
393 | } |
394 | |
395 | SecureMessage::Type SecureMessage::type() const |
396 | { |
397 | return d->c->type(); |
398 | } |
399 | |
400 | bool SecureMessage::canSignMultiple() const |
401 | { |
402 | return d->c->canSignMultiple(); |
403 | } |
404 | |
405 | bool SecureMessage::canClearsign() const |
406 | { |
407 | return (type() == OpenPGP); |
408 | } |
409 | |
410 | bool SecureMessage::canSignAndEncrypt() const |
411 | { |
412 | return (type() == OpenPGP); |
413 | } |
414 | |
415 | void SecureMessage::reset() |
416 | { |
417 | d->reset(mode: ResetAll); |
418 | } |
419 | |
420 | bool SecureMessage::bundleSignerEnabled() const |
421 | { |
422 | return d->bundleSigner; |
423 | } |
424 | |
425 | bool SecureMessage::smimeAttributesEnabled() const |
426 | { |
427 | return d->smime; |
428 | } |
429 | |
430 | SecureMessage::Format SecureMessage::format() const |
431 | { |
432 | return d->format; |
433 | } |
434 | |
435 | SecureMessageKeyList SecureMessage::recipientKeys() const |
436 | { |
437 | return d->to; |
438 | } |
439 | |
440 | SecureMessageKeyList SecureMessage::signerKeys() const |
441 | { |
442 | return d->from; |
443 | } |
444 | |
445 | void SecureMessage::setBundleSignerEnabled(bool b) |
446 | { |
447 | d->bundleSigner = b; |
448 | } |
449 | |
450 | void SecureMessage::setSMIMEAttributesEnabled(bool b) |
451 | { |
452 | d->smime = b; |
453 | } |
454 | |
455 | void SecureMessage::setFormat(Format f) |
456 | { |
457 | d->format = f; |
458 | } |
459 | |
460 | void SecureMessage::setRecipient(const SecureMessageKey &key) |
461 | { |
462 | d->to = SecureMessageKeyList() << key; |
463 | } |
464 | |
465 | void SecureMessage::setRecipients(const SecureMessageKeyList &keys) |
466 | { |
467 | d->to = keys; |
468 | } |
469 | |
470 | void SecureMessage::setSigner(const SecureMessageKey &key) |
471 | { |
472 | d->from = SecureMessageKeyList() << key; |
473 | } |
474 | |
475 | void SecureMessage::setSigners(const SecureMessageKeyList &keys) |
476 | { |
477 | d->from = keys; |
478 | } |
479 | |
480 | void SecureMessage::startEncrypt() |
481 | { |
482 | d->reset(mode: ResetSessionAndData); |
483 | d->c->setupEncrypt(d->to); |
484 | d->c->start(f: d->format, op: MessageContext::Encrypt); |
485 | } |
486 | |
487 | void SecureMessage::startDecrypt() |
488 | { |
489 | d->reset(mode: ResetSessionAndData); |
490 | d->c->start(f: d->format, op: MessageContext::Decrypt); |
491 | } |
492 | |
493 | void SecureMessage::startSign(SignMode m) |
494 | { |
495 | d->reset(mode: ResetSessionAndData); |
496 | d->c->setupSign(keys: d->from, m, bundleSigner: d->bundleSigner, smime: d->smime); |
497 | d->c->start(f: d->format, op: MessageContext::Sign); |
498 | } |
499 | |
500 | void SecureMessage::startVerify(const QByteArray &sig) |
501 | { |
502 | d->reset(mode: ResetSessionAndData); |
503 | if (!sig.isEmpty()) |
504 | d->c->setupVerify(sig); |
505 | d->c->start(f: d->format, op: MessageContext::Verify); |
506 | } |
507 | |
508 | void SecureMessage::startSignAndEncrypt() |
509 | { |
510 | d->reset(mode: ResetSessionAndData); |
511 | d->c->setupEncrypt(d->to); |
512 | d->c->setupSign(keys: d->from, m: Message, bundleSigner: d->bundleSigner, smime: d->smime); |
513 | d->c->start(f: d->format, op: MessageContext::SignAndEncrypt); |
514 | } |
515 | |
516 | void SecureMessage::update(const QByteArray &in) |
517 | { |
518 | d->c->update(in); |
519 | } |
520 | |
521 | QByteArray SecureMessage::read() |
522 | { |
523 | const QByteArray a = d->in; |
524 | d->in.clear(); |
525 | return a; |
526 | } |
527 | |
528 | int SecureMessage::bytesAvailable() const |
529 | { |
530 | return d->in.size(); |
531 | } |
532 | |
533 | void SecureMessage::end() |
534 | { |
535 | d->c->end(); |
536 | } |
537 | |
538 | bool SecureMessage::waitForFinished(int msecs) |
539 | { |
540 | d->c->waitForFinished(msecs); |
541 | d->updated(); |
542 | return d->success; |
543 | } |
544 | |
545 | bool SecureMessage::success() const |
546 | { |
547 | return d->success; |
548 | } |
549 | |
550 | SecureMessage::Error SecureMessage::errorCode() const |
551 | { |
552 | return d->errorCode; |
553 | } |
554 | |
555 | QByteArray SecureMessage::signature() const |
556 | { |
557 | return d->detachedSig; |
558 | } |
559 | |
560 | QString SecureMessage::hashName() const |
561 | { |
562 | return d->hashName; |
563 | } |
564 | |
565 | bool SecureMessage::wasSigned() const |
566 | { |
567 | return !d->signers.isEmpty(); |
568 | } |
569 | |
570 | bool SecureMessage::verifySuccess() const |
571 | { |
572 | // if we're not done or there were no signers, then return false |
573 | if (!d->success || d->signers.isEmpty()) |
574 | return false; |
575 | |
576 | // make sure all signers have a valid signature |
577 | for (int n = 0; n < d->signers.count(); ++n) { |
578 | if (d->signers[n].identityResult() != SecureMessageSignature::Valid) |
579 | return false; |
580 | } |
581 | return true; |
582 | } |
583 | |
584 | SecureMessageSignature SecureMessage::signer() const |
585 | { |
586 | if (d->signers.isEmpty()) |
587 | return SecureMessageSignature(); |
588 | |
589 | return d->signers.first(); |
590 | } |
591 | |
592 | SecureMessageSignatureList SecureMessage::signers() const |
593 | { |
594 | return d->signers; |
595 | } |
596 | |
597 | QString SecureMessage::diagnosticText() const |
598 | { |
599 | return d->dtext; |
600 | } |
601 | |
602 | //---------------------------------------------------------------------------- |
603 | // SecureMessageSystem |
604 | //---------------------------------------------------------------------------- |
605 | SecureMessageSystem::SecureMessageSystem(QObject *parent, const QString &type, const QString &provider) |
606 | : QObject(parent) |
607 | , Algorithm(type, provider) |
608 | { |
609 | } |
610 | |
611 | SecureMessageSystem::~SecureMessageSystem() |
612 | { |
613 | } |
614 | |
615 | //---------------------------------------------------------------------------- |
616 | // OpenPGP |
617 | //---------------------------------------------------------------------------- |
618 | OpenPGP::OpenPGP(QObject *parent, const QString &provider) |
619 | : SecureMessageSystem(parent, QStringLiteral("openpgp" ), provider) |
620 | { |
621 | } |
622 | |
623 | OpenPGP::~OpenPGP() |
624 | { |
625 | } |
626 | |
627 | //---------------------------------------------------------------------------- |
628 | // CMS |
629 | //---------------------------------------------------------------------------- |
630 | class CMS::Private |
631 | { |
632 | public: |
633 | CertificateCollection trusted, untrusted; |
634 | SecureMessageKeyList privateKeys; |
635 | }; |
636 | |
637 | CMS::CMS(QObject *parent, const QString &provider) |
638 | : SecureMessageSystem(parent, QStringLiteral("cms" ), provider) |
639 | { |
640 | d = new Private; |
641 | } |
642 | |
643 | CMS::~CMS() |
644 | { |
645 | delete d; |
646 | } |
647 | |
648 | CertificateCollection CMS::trustedCertificates() const |
649 | { |
650 | return d->trusted; |
651 | } |
652 | |
653 | CertificateCollection CMS::untrustedCertificates() const |
654 | { |
655 | return d->untrusted; |
656 | } |
657 | |
658 | SecureMessageKeyList CMS::privateKeys() const |
659 | { |
660 | return d->privateKeys; |
661 | } |
662 | |
663 | void CMS::setTrustedCertificates(const CertificateCollection &trusted) |
664 | { |
665 | d->trusted = trusted; |
666 | static_cast<SMSContext *>(context())->setTrustedCertificates(trusted); |
667 | } |
668 | |
669 | void CMS::setUntrustedCertificates(const CertificateCollection &untrusted) |
670 | { |
671 | d->untrusted = untrusted; |
672 | static_cast<SMSContext *>(context())->setUntrustedCertificates(untrusted); |
673 | } |
674 | |
675 | void CMS::setPrivateKeys(const SecureMessageKeyList &keys) |
676 | { |
677 | d->privateKeys = keys; |
678 | static_cast<SMSContext *>(context())->setPrivateKeys(keys); |
679 | } |
680 | |
681 | } |
682 | |
683 | #include "qca_securemessage.moc" |
684 | |