1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "CTVerifyResult.h"
9 #include "PSMIPCCommon.h"
10
11 namespace mozilla {
12 namespace psm {
13
WrapPrivateKeyInfoWithEmptyPassword(SECKEYPrivateKey * pk)14 SECItem* WrapPrivateKeyInfoWithEmptyPassword(
15 SECKEYPrivateKey* pk) /* encrypt this private key */
16 {
17 if (!pk) {
18 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
19 return nullptr;
20 }
21
22 UniquePK11SlotInfo slot(PK11_GetInternalSlot());
23 if (!slot) {
24 return nullptr;
25 }
26
27 // For private keys, NSS cannot export anything other than RSA, but we need EC
28 // also. So, we use the private key encryption function to serialize instead,
29 // using a hard-coded dummy password; this is not intended to provide any
30 // additional security, it just works around a limitation in NSS.
31 SECItem dummyPassword = {siBuffer, nullptr, 0};
32 UniqueSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
33 slot.get(), SEC_OID_AES_128_CBC, &dummyPassword, pk, 1, nullptr));
34
35 if (!epki) {
36 return nullptr;
37 }
38
39 return SEC_ASN1EncodeItem(
40 nullptr, nullptr, epki.get(),
41 NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false));
42 }
43
UnwrapPrivateKeyInfoWithEmptyPassword(SECItem * derPKI,const UniqueCERTCertificate & aCert,SECKEYPrivateKey ** privk)44 SECStatus UnwrapPrivateKeyInfoWithEmptyPassword(
45 SECItem* derPKI, const UniqueCERTCertificate& aCert,
46 SECKEYPrivateKey** privk) {
47 if (!derPKI || !aCert || !privk) {
48 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
49 return SECFailure;
50 }
51
52 UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(aCert.get()));
53 // This is a pointer to data inside publicKey
54 SECItem* publicValue = nullptr;
55 switch (publicKey->keyType) {
56 case dsaKey:
57 publicValue = &publicKey->u.dsa.publicValue;
58 break;
59 case dhKey:
60 publicValue = &publicKey->u.dh.publicValue;
61 break;
62 case rsaKey:
63 publicValue = &publicKey->u.rsa.modulus;
64 break;
65 case ecKey:
66 publicValue = &publicKey->u.ec.publicValue;
67 break;
68 default:
69 MOZ_ASSERT(false);
70 PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
71 return SECFailure;
72 }
73
74 UniquePK11SlotInfo slot(PK11_GetInternalSlot());
75 if (!slot) {
76 return SECFailure;
77 }
78
79 UniquePLArenaPool temparena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
80 if (!temparena) {
81 return SECFailure;
82 }
83
84 SECKEYEncryptedPrivateKeyInfo* epki =
85 PORT_ArenaZNew(temparena.get(), SECKEYEncryptedPrivateKeyInfo);
86 if (!epki) {
87 return SECFailure;
88 }
89
90 SECStatus rv = SEC_ASN1DecodeItem(
91 temparena.get(), epki,
92 NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false), derPKI);
93 if (rv != SECSuccess) {
94 // If SEC_ASN1DecodeItem fails, we cannot assume anything about the
95 // validity of the data in epki. The best we can do is free the arena
96 // and return.
97 return rv;
98 }
99
100 // See comment in WrapPrivateKeyInfoWithEmptyPassword about this
101 // dummy password stuff.
102 SECItem dummyPassword = {siBuffer, nullptr, 0};
103 return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
104 slot.get(), epki, &dummyPassword, nullptr, publicValue, false, false,
105 publicKey->keyType, KU_ALL, privk, nullptr);
106 }
107
SerializeClientCertAndKey(const UniqueCERTCertificate & aCert,const UniqueSECKEYPrivateKey & aKey,ByteArray & aOutSerializedCert,ByteArray & aOutSerializedKey)108 void SerializeClientCertAndKey(const UniqueCERTCertificate& aCert,
109 const UniqueSECKEYPrivateKey& aKey,
110 ByteArray& aOutSerializedCert,
111 ByteArray& aOutSerializedKey) {
112 if (!aCert || !aKey) {
113 return;
114 }
115
116 UniqueSECItem derPki(WrapPrivateKeyInfoWithEmptyPassword(aKey.get()));
117 if (!derPki) {
118 return;
119 }
120
121 aOutSerializedCert.data().AppendElements(aCert->derCert.data,
122 aCert->derCert.len);
123 aOutSerializedKey.data().AppendElements(derPki->data, derPki->len);
124 }
125
DeserializeClientCertAndKey(const ByteArray & aSerializedCert,const ByteArray & aSerializedKey,UniqueCERTCertificate & aOutCert,UniqueSECKEYPrivateKey & aOutKey)126 void DeserializeClientCertAndKey(const ByteArray& aSerializedCert,
127 const ByteArray& aSerializedKey,
128 UniqueCERTCertificate& aOutCert,
129 UniqueSECKEYPrivateKey& aOutKey) {
130 if (aSerializedCert.data().IsEmpty() || aSerializedKey.data().IsEmpty()) {
131 return;
132 }
133
134 SECItem item = {siBuffer,
135 const_cast<uint8_t*>(aSerializedCert.data().Elements()),
136 static_cast<unsigned int>(aSerializedCert.data().Length())};
137
138 UniqueCERTCertificate cert(CERT_NewTempCertificate(
139 CERT_GetDefaultCertDB(), &item, nullptr, false, true));
140
141 if (!cert) {
142 return;
143 }
144
145 SECItem derPKI = {siBuffer,
146 const_cast<uint8_t*>(aSerializedKey.data().Elements()),
147 static_cast<unsigned int>(aSerializedKey.data().Length())};
148
149 SECKEYPrivateKey* privateKey;
150 if (UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) !=
151 SECSuccess) {
152 MOZ_ASSERT(false);
153 return;
154 }
155
156 aOutCert = std::move(cert);
157 aOutKey.reset(privateKey);
158 }
159
160 } // namespace psm
161 } // namespace mozilla
162