/src/qtbase/src/plugins/tls/shared/qtlskey_base.cpp
Line | Count | Source |
1 | | // Copyright (C) 2021 The Qt Company Ltd. |
2 | | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include "qtlskey_base_p.h" |
6 | | #include "qasn1element_p.h" |
7 | | |
8 | | QT_BEGIN_NAMESPACE |
9 | | |
10 | | namespace QTlsPrivate { |
11 | | |
12 | | QByteArray TlsKeyBase::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const |
13 | 0 | { |
14 | 0 | QByteArray pem(der.toBase64()); |
15 | |
|
16 | 0 | const int lineWidth = 64; // RFC 1421 |
17 | 0 | const int newLines = pem.size() / lineWidth; |
18 | 0 | const bool rem = pem.size() % lineWidth; |
19 | |
|
20 | 0 | for (int i = 0; i < newLines; ++i) |
21 | 0 | pem.insert((i + 1) * lineWidth + i, '\n'); |
22 | 0 | if (rem) |
23 | 0 | pem.append('\n'); |
24 | |
|
25 | 0 | QByteArray extra; |
26 | 0 | if (!headers.isEmpty()) { |
27 | 0 | QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd(); |
28 | 0 | do { |
29 | 0 | --it; |
30 | 0 | extra += it.key() + ": " + it.value() + '\n'; |
31 | 0 | } while (it != headers.constBegin()); |
32 | 0 | extra += '\n'; |
33 | 0 | } |
34 | |
|
35 | 0 | if (isEncryptedPkcs8(der)) { |
36 | 0 | pem.prepend(pkcs8Header(true) + '\n' + extra); |
37 | 0 | pem.append(pkcs8Footer(true) + '\n'); |
38 | 0 | } else if (isPkcs8()) { |
39 | 0 | pem.prepend(pkcs8Header(false) + '\n' + extra); |
40 | 0 | pem.append(pkcs8Footer(false) + '\n'); |
41 | 0 | } else { |
42 | 0 | pem.prepend(pemHeader() + '\n' + extra); |
43 | 0 | pem.append(pemFooter() + '\n'); |
44 | 0 | } |
45 | |
|
46 | 0 | return pem; |
47 | 0 | } |
48 | | |
49 | | QByteArray TlsKeyBase::pkcs8Header(bool encrypted) |
50 | 0 | { |
51 | 0 | return encrypted |
52 | 0 | ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----") |
53 | 0 | : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----"); |
54 | 0 | } |
55 | | |
56 | | QByteArray TlsKeyBase::pkcs8Footer(bool encrypted) |
57 | 0 | { |
58 | 0 | return encrypted |
59 | 0 | ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----") |
60 | 0 | : QByteArrayLiteral("-----END PRIVATE KEY-----"); |
61 | 0 | } |
62 | | |
63 | | bool TlsKeyBase::isEncryptedPkcs8(const QByteArray &der) |
64 | 0 | { |
65 | 0 | static const QList<QByteArray> pbes1OIds { |
66 | | // PKCS5 |
67 | 0 | { PKCS5_MD2_DES_CBC_OID }, { PKCS5_MD2_RC2_CBC_OID }, { PKCS5_MD5_DES_CBC_OID }, |
68 | 0 | { PKCS5_MD5_RC2_CBC_OID }, { PKCS5_SHA1_DES_CBC_OID }, { PKCS5_SHA1_RC2_CBC_OID }, |
69 | 0 | }; |
70 | 0 | QAsn1Element elem; |
71 | 0 | if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType) |
72 | 0 | return false; |
73 | | |
74 | 0 | const auto items = elem.toList(); |
75 | 0 | if (items.size() != 2 |
76 | 0 | || items[0].type() != QAsn1Element::SequenceType |
77 | 0 | || items[1].type() != QAsn1Element::OctetStringType) { |
78 | 0 | return false; |
79 | 0 | } |
80 | | |
81 | 0 | const auto encryptionSchemeContainer = items[0].toList(); |
82 | 0 | if (encryptionSchemeContainer.size() != 2 |
83 | 0 | || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType |
84 | 0 | || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) { |
85 | 0 | return false; |
86 | 0 | } |
87 | | |
88 | 0 | const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId(); |
89 | 0 | return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID |
90 | 0 | || pbes1OIds.contains(encryptionScheme) |
91 | 0 | || encryptionScheme.startsWith(PKCS12_OID); |
92 | 0 | } |
93 | | |
94 | | } // namespace QTlsPrivate |
95 | | |
96 | | QT_END_NAMESPACE |
97 | | |
98 | | |