1 // Copyright 2018 The BoringSSL Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <openssl/pem.h>
16 
17 #include <functional>
18 
19 #include <gtest/gtest.h>
20 
21 #include <openssl/bio.h>
22 #include <openssl/cipher.h>
23 #include <openssl/err.h>
24 #include <openssl/rsa.h>
25 
26 #include "../test/test_util.h"
27 
28 
29 namespace {
30 
31 // Test that implausible ciphers, notably an IV-less RC4, aren't allowed in PEM.
32 // This is a regression test for https://github.com/openssl/openssl/issues/6347,
33 // though our fix differs from upstream.
TEST(PEMTest,NoRC4)34 TEST(PEMTest, NoRC4) {
35   static const char kPEM[] =
36       "-----BEGIN RSA PUBLIC KEY-----\n"
37       "Proc-Type: 4,ENCRYPTED\n"
38       "DEK-Info: RC4 -\n"
39       "extra-info\n"
40       "router-signature\n"
41       "\n"
42       "Z1w=\n"
43       "-----END RSA PUBLIC KEY-----\n";
44   bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kPEM, sizeof(kPEM) - 1));
45   ASSERT_TRUE(bio);
46   bssl::UniquePtr<RSA> rsa(PEM_read_bio_RSAPublicKey(
47       bio.get(), nullptr, nullptr, const_cast<char *>("password")));
48   EXPECT_FALSE(rsa);
49   EXPECT_TRUE(
50       ErrorEquals(ERR_get_error(), ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION));
51 }
52 
DecodePEMBytes(const char * pem)53 static std::vector<uint8_t> DecodePEMBytes(const char *pem) {
54   bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
55   char *name, *header;
56   uint8_t *data;
57   long len;
58   if (bio == nullptr ||  //
59       !PEM_read_bio(bio.get(), &name, &header, &data, &len)) {
60     return {};
61   }
62   bssl::UniquePtr<char> free_name(name), free_header(header);
63   bssl::UniquePtr<uint8_t> free_data(data);
64   return std::vector<uint8_t>(data, data + len);
65 }
66 
TEST(PEMTest,DecryptPassword)67 TEST(PEMTest, DecryptPassword) {
68   // A private key encrypted with the password "password", encrypted at the
69   // PKCS#8 level.
70   static const char kEncryptedPEM[] = R"(
71 -----BEGIN ENCRYPTED PRIVATE KEY-----
72 MIHeMEkGCSqGSIb3DQEFDTA8MBsGCSqGSIb3DQEFDDAOBAjnhMUlb9deeQICCAAw
73 HQYJYIZIAWUDBAECBBAO8j5GA5VK8wjvNrzp/iVhBIGQyQKFfFKlFhxiDkFfyhUc
74 nPLr0eboQOz8eIaTW1Rblo/qDkQwNtONyfYn909SoIP7iU8UehcBG1UQe41WvQpu
75 yRKYQteoWSzFl+yzktL2Y/25K7Uc+f2NScjdonYMZ+9/m1HGmEzKO+Hz28cAsJL7
76 rH2gQ0lkxr1GtW77m2rfMKKuGYhpkgjWUbzJwP9v3iq+
77 -----END ENCRYPTED PRIVATE KEY-----
78 )";
79   // The same key and password, but encrypted at the PEM level.
80   static const char kEncryptedPEM2[] = R"(
81 -----BEGIN EC PRIVATE KEY-----
82 Proc-Type: 4,ENCRYPTED
83 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C1123
84 
85 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
86 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
87 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
88 -----END EC PRIVATE KEY-----
89 )";
90 
91   for (const char *pem : {kEncryptedPEM, kEncryptedPEM2}) {
92     SCOPED_TRACE(pem);
93     // Decrypt with the correct password.
94     {
95       bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
96       ASSERT_TRUE(bio);
97       bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(
98           bio.get(), nullptr, nullptr, const_cast<char *>("password")));
99       EXPECT_TRUE(pkey);
100     }
101 
102     // Decrypt with the wrong password.
103     {
104       bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
105       ASSERT_TRUE(bio);
106       bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(
107           bio.get(), nullptr, nullptr, const_cast<char *>("wrong")));
108       EXPECT_FALSE(pkey);
109       EXPECT_TRUE(
110           ErrorEquals(ERR_peek_error(), ERR_LIB_CIPHER, CIPHER_R_BAD_DECRYPT));
111       ERR_clear_error();
112     }
113 
114     // If the caller did not pass in a password, we should not proceed to try to
115     // decrypt.
116     {
117       bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
118       ASSERT_TRUE(bio);
119       bssl::UniquePtr<EVP_PKEY> pkey(
120           PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
121       EXPECT_FALSE(pkey);
122       EXPECT_TRUE(
123           ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ));
124       ERR_clear_error();
125     }
126 
127     // If the password, with a NUL terminator, does not fit in the internal
128     // buffer used by the PEM library, the PEM library should notice.
129     {
130       std::string too_long(PEM_BUFSIZE, 'a');
131       bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
132       ASSERT_TRUE(bio);
133       bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(
134           bio.get(), nullptr, nullptr, const_cast<char *>(too_long.c_str())));
135       EXPECT_FALSE(pkey);
136       EXPECT_TRUE(
137           ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ));
138       ERR_clear_error();
139     }
140   }
141 
142   // |d2i_PKCS8PrivateKey_bio| should also be able to manage the password
143   // callback correctly.
144   std::vector<uint8_t> bytes = DecodePEMBytes(kEncryptedPEM);
145   ASSERT_FALSE(bytes.empty());
146   {
147     bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(bytes.data(), bytes.size()));
148     ASSERT_TRUE(bio);
149     bssl::UniquePtr<EVP_PKEY> pkey(d2i_PKCS8PrivateKey_bio(
150         bio.get(), nullptr, nullptr, const_cast<char *>("password")));
151     EXPECT_TRUE(pkey);
152   }
153 
154   {
155     bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(bytes.data(), bytes.size()));
156     ASSERT_TRUE(bio);
157     bssl::UniquePtr<EVP_PKEY> pkey(
158         d2i_PKCS8PrivateKey_bio(bio.get(), nullptr, nullptr, nullptr));
159     EXPECT_FALSE(pkey);
160     EXPECT_TRUE(
161         ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ));
162     ERR_clear_error();
163   }
164 
165   {
166     std::string too_long(PEM_BUFSIZE, 'a');
167     bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(bytes.data(), bytes.size()));
168     ASSERT_TRUE(bio);
169     bssl::UniquePtr<EVP_PKEY> pkey(d2i_PKCS8PrivateKey_bio(
170         bio.get(), nullptr, nullptr, const_cast<char *>(too_long.c_str())));
171     EXPECT_FALSE(pkey);
172     EXPECT_TRUE(
173         ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ));
174     ERR_clear_error();
175   }
176 
177   // A private key encrypted with the empty password, encrypted at the PKCS#8
178   // level.
179   static const char kEncryptedPEMEmpty[] = R"(
180 -----BEGIN ENCRYPTED PRIVATE KEY-----
181 MIH0MF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBAXiHC8iDcjzF0I+D2g
182 zJOcAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBAgQQwupOMi8DtEWiuXt5
183 Odla9QSBkC37uJuG7HSCOyTVCEW76Kmf7GoH+Ou17bDAp6NGwm3KLxRfFoExki9g
184 hyLzdarBnhRbPqwMixhaQ2AtkpoSmjristGzZ9U7Y+TM3NnCA4+bu1TckdBn0g+Q
185 fvZI9eydS9buA0deGxCUytrMWrR3PxS1yoXBywMDJTom8u5hvvvkJ9WcNzUVRf0D
186 6z5NHHiXsQ==
187 -----END ENCRYPTED PRIVATE KEY-----
188 )";
189   // THe same key and password, but encrypted at the PEM level.
190   static const char kEncryptedPEMEmpty2[] = R"(
191 -----BEGIN EC PRIVATE KEY-----
192 Proc-Type: 4,ENCRYPTED
193 DEK-Info: AES-128-CBC,A9505A7DD5C3B51D8AACED18F5758256
194 
195 yfJKjep7Koj8hU/PtGC+NNXSNbItQ2zyeXDMVoazffraoDGMg6g1hFPPjg9reC+J
196 iQQIf9uACF27zi9fpWwbszszimrxl0u6n0ddBXizcK6xzkTvk3PZ67Vz1KYmotwC
197 XjgdgSEeixwKhDOuHKFdlFGP/7sw5GHlK3jPSpqi2gI=
198 -----END EC PRIVATE KEY-----
199 )";
200 
201   for (const char *pem : {kEncryptedPEMEmpty, kEncryptedPEMEmpty2}) {
202     SCOPED_TRACE(pem);
203 
204     // The empty password should be correctly interpreted as a password.
205     {
206       bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, -1));
207       ASSERT_TRUE(bio);
208       bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(
209           bio.get(), nullptr, nullptr, const_cast<char *>("")));
210       EXPECT_TRUE(pkey);
211     }
212   }
213 
214   // |d2i_PKCS8PrivateKey_bio| should also be able to manage the password
215   // callback correctly.
216   bytes = DecodePEMBytes(kEncryptedPEMEmpty);
217   {
218     ASSERT_FALSE(bytes.empty());
219     bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(bytes.data(), bytes.size()));
220     ASSERT_TRUE(bio);
221     bssl::UniquePtr<EVP_PKEY> pkey(d2i_PKCS8PrivateKey_bio(
222         bio.get(), nullptr, nullptr, const_cast<char *>("")));
223     EXPECT_TRUE(pkey);
224   }
225 }
226 
TEST(PEMTest,EncryptPassword)227 TEST(PEMTest, EncryptPassword) {
228   static const char kKey[] = R"(
229 -----BEGIN PRIVATE KEY-----
230 MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBw8IcnrUoEqc3VnJ
231 TYlodwi1b8ldMHcO6NHJzgqLtGqhRANCAATmK2niv2Wfl74vHg2UikzVl2u3qR4N
232 Rvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUdfvGULUvPciLB
233 -----END PRIVATE KEY-----
234 )";
235   bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKey, -1));
236   ASSERT_TRUE(bio);
237   bssl::UniquePtr<EVP_PKEY> pkey(
238       PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
239   EXPECT_TRUE(pkey);
240 
241   // There are many ways to encrypt a PEM blob with a password.
242   struct PasswordMethod {
243     const char *name;
244     std::function<bool(BIO *, const char *)> func;
245     bool is_callback;
246   };
247   const PasswordMethod kPasswordMethods[] = {
248       {"PKCS#8 encryption, password from param",
249        [&](BIO *out, const char *pass) -> bool {
250          return PEM_write_bio_PrivateKey(
251              out, pkey.get(), EVP_aes_128_cbc(),
252              reinterpret_cast<const unsigned char *>(pass),
253              pass == nullptr ? 0 : strlen(pass), nullptr, nullptr);
254        },
255        /*is_callback=*/false},
256       {"PKCS#8 encryption, password from callback",
257        [&](BIO *out, const char *pass) -> bool {
258          return PEM_write_bio_PrivateKey(out, pkey.get(), EVP_aes_128_cbc(),
259                                          nullptr, 0, nullptr,
260                                          const_cast<char *>(pass));
261        },
262        /*is_callback=*/true},
263       {"PEM-level encryption, password from param",
264        [&](BIO *out, const char *pass) -> bool {
265          return PEM_write_bio_ECPrivateKey(
266              out, EVP_PKEY_get0_EC_KEY(pkey.get()), EVP_aes_128_cbc(), nullptr,
267              0, nullptr, const_cast<char *>(pass));
268        },
269        /*is_callback=*/false},
270       {"PKCS#8 encryption, password from callback",
271        [&](BIO *out, const char *pass) -> bool {
272          return PEM_write_bio_ECPrivateKey(
273              out, EVP_PKEY_get0_EC_KEY(pkey.get()), EVP_aes_128_cbc(), nullptr,
274              0, nullptr, const_cast<char *>(pass));
275        },
276        /*is_callback=*/true},
277   };
278   for (const auto &p : kPasswordMethods) {
279     SCOPED_TRACE(p.name);
280 
281     // Encrypting the private key with a password should work.
282     bio.reset(BIO_new(BIO_s_mem()));
283     ASSERT_TRUE(bio);
284     ASSERT_TRUE(p.func(bio.get(), "password"));
285 
286     // Check we can decrypt it.
287     bssl::UniquePtr<EVP_PKEY> pkey2(PEM_read_bio_PrivateKey(
288         bio.get(), nullptr, nullptr, const_cast<char *>("password")));
289     ASSERT_TRUE(pkey2);
290 
291     // The empty string is a valid password.
292     bio.reset(BIO_new(BIO_s_mem()));
293     ASSERT_TRUE(bio);
294     ASSERT_TRUE(p.func(bio.get(), ""));
295 
296     // Check we can decrypt it.
297     pkey2.reset(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr,
298                                         const_cast<char *>("")));
299     ASSERT_TRUE(pkey2);
300 
301     // Check error-handling when the password is specified via the callback.
302     if (p.is_callback) {
303       bio.reset(BIO_new(BIO_s_mem()));
304       ASSERT_TRUE(bio);
305       EXPECT_FALSE(p.func(bio.get(), nullptr));
306       EXPECT_TRUE(ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_READ_KEY));
307       ERR_clear_error();
308 
309       std::string too_long(PEM_BUFSIZE, 'a');
310       bio.reset(BIO_new(BIO_s_mem()));
311       ASSERT_TRUE(bio);
312       EXPECT_FALSE(p.func(bio.get(), too_long.c_str()));
313       EXPECT_TRUE(ErrorEquals(ERR_peek_error(), ERR_LIB_PEM, PEM_R_READ_KEY));
314       ERR_clear_error();
315     }
316   }
317 }
318 
TEST(PEMTest,BadHeaders)319 TEST(PEMTest, BadHeaders) {
320   const struct {
321     const char *pem;
322     int err_lib, err_reason;
323   } kTests[] = {
324       // Proc-Type must be the first header.
325       {
326           R"(
327 -----BEGIN EC PRIVATE KEY-----
328 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C1123
329 Proc-Type: 4,ENCRYPTED
330 
331 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
332 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
333 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
334 -----END EC PRIVATE KEY-----
335 )",
336           ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE},
337       // Unsupported Proc-Type version.
338       {
339           R"(
340 -----BEGIN EC PRIVATE KEY-----
341 Proc-Type: 5,ENCRYPTED
342 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C1123
343 
344 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
345 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
346 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
347 -----END EC PRIVATE KEY-----
348 )",
349           ERR_LIB_PEM, PEM_R_UNSUPPORTED_PROC_TYPE_VERSION},
350       // Unsupported Proc-Type version.
351       {
352           R"(
353 -----BEGIN EC PRIVATE KEY-----
354 Proc-Type: 42,ENCRYPTED
355 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C1123
356 
357 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
358 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
359 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
360 -----END EC PRIVATE KEY-----
361 )",
362           ERR_LIB_PEM, PEM_R_UNSUPPORTED_PROC_TYPE_VERSION},
363       // Unsupported Proc-Type.
364       {
365           R"(
366 -----BEGIN EC PRIVATE KEY-----
367 Proc-Type: 4,MIC-ONLY
368 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C1123
369 
370 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
371 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
372 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
373 -----END EC PRIVATE KEY-----
374 )",
375           ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED},
376       // Missing DEK-Info.
377       {
378           R"(
379 -----BEGIN EC PRIVATE KEY-----
380 Proc-Type: 4,ENCRYPTED
381 
382 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
383 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
384 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
385 -----END EC PRIVATE KEY-----
386 )",
387           ERR_LIB_PEM, PEM_R_NOT_DEK_INFO},
388       // Unsupported cipher.
389       {
390           R"(
391 -----BEGIN EC PRIVATE KEY-----
392 Proc-Type: 4,ENCRYPTED
393 DEK-Info: AES-127-CBC,B3B2988AECAE6EAB0D043105994C1123
394 
395 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
396 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
397 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
398 -----END EC PRIVATE KEY-----
399 )",
400           ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION},
401       // IV is not hex.
402       {
403           R"(
404 -----BEGIN EC PRIVATE KEY-----
405 Proc-Type: 4,ENCRYPTED
406 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C112Z
407 
408 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
409 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
410 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
411 -----END EC PRIVATE KEY-----
412 )",
413           ERR_LIB_PEM, PEM_R_BAD_IV_CHARS},
414       // Truncated IV.
415       {
416           R"(
417 -----BEGIN EC PRIVATE KEY-----
418 Proc-Type: 4,ENCRYPTED
419 DEK-Info: AES-128-CBC,B3B2988AECAE6EAB0D043105994C112
420 
421 RK7DUIGDHWTFh2rpTX+dR88hUyC1PyDlIULiNCkuWFwHrJbc1gM6hMVOKmU196XC
422 iITrIKmilFm9CPD6Tpfk/NhI/QPxyJlk1geIkxpvUZ2FCeMuYI1To14oYOUKv14q
423 wr6JtaX2G+pOmwcSPymZC4u2TncAP7KHgS8UGcMw8CE=
424 -----END EC PRIVATE KEY-----
425 )",
426           ERR_LIB_PEM, PEM_R_BAD_IV_CHARS},
427   };
428   for (const auto &t : kTests) {
429     SCOPED_TRACE(t.pem);
430     bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(t.pem, -1));
431     ASSERT_TRUE(bio);
432     bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(
433         bio.get(), nullptr, nullptr, const_cast<char *>("password")));
434     EXPECT_FALSE(pkey);
435     EXPECT_TRUE(ErrorEquals(ERR_get_error(), t.err_lib, t.err_reason));
436     ERR_clear_error();
437   }
438 }
439 
440 }  // namespace
441