| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1425,4 +1425,213 @@ DataPointer pbkdf2(const EVP_MD* md, | |||
| 1425 | 1425 | return {}; | |
| 1426 | 1426 | } | |
| 1427 | 1427 | ||
| 1428 | + // ============================================================================ | ||
| 1429 | + | ||
| 1430 | + EVPKeyPointer EVPKeyPointer::New() { | ||
| 1431 | + return EVPKeyPointer(EVP_PKEY_new()); | ||
| 1432 | + } | ||
| 1433 | + | ||
| 1434 | + EVPKeyPointer EVPKeyPointer::NewRawPublic(int id, const Buffer<const unsigned char>& data) { | ||
| 1435 | + if (id == 0) return {}; | ||
| 1436 | + return EVPKeyPointer(EVP_PKEY_new_raw_public_key(id, nullptr, data.data, data.len)); | ||
| 1437 | + } | ||
| 1438 | + | ||
| 1439 | + EVPKeyPointer EVPKeyPointer::NewRawPrivate(int id, const Buffer<const unsigned char>& data) { | ||
| 1440 | + if (id == 0) return {}; | ||
| 1441 | + return EVPKeyPointer(EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len)); | ||
| 1442 | + } | ||
| 1443 | + | ||
| 1444 | + EVPKeyPointer::EVPKeyPointer(EVP_PKEY* pkey) : pkey_(pkey) {} | ||
| 1445 | + | ||
| 1446 | + EVPKeyPointer::EVPKeyPointer(EVPKeyPointer&& other) noexcept | ||
| 1447 | + : pkey_(other.release()) {} | ||
| 1448 | + | ||
| 1449 | + EVPKeyPointer& EVPKeyPointer::operator=(EVPKeyPointer&& other) noexcept { | ||
| 1450 | + if (this == &other) return *this; | ||
| 1451 | + this->~EVPKeyPointer(); | ||
| 1452 | + return *new (this) EVPKeyPointer(std::move(other)); | ||
| 1453 | + } | ||
| 1454 | + | ||
| 1455 | + EVPKeyPointer::~EVPKeyPointer() { reset(); } | ||
| 1456 | + | ||
| 1457 | + void EVPKeyPointer::reset(EVP_PKEY* pkey) { | ||
| 1458 | + pkey_.reset(pkey); | ||
| 1459 | + } | ||
| 1460 | + | ||
| 1461 | + EVP_PKEY* EVPKeyPointer::release() { | ||
| 1462 | + return pkey_.release(); | ||
| 1463 | + } | ||
| 1464 | + | ||
| 1465 | + int EVPKeyPointer::id(const EVP_PKEY* key) { | ||
| 1466 | + if (key == nullptr) return 0; | ||
| 1467 | + return EVP_PKEY_id(key); | ||
| 1468 | + } | ||
| 1469 | + | ||
| 1470 | + int EVPKeyPointer::base_id(const EVP_PKEY* key) { | ||
| 1471 | + if (key == nullptr) return 0; | ||
| 1472 | + return EVP_PKEY_base_id(key); | ||
| 1473 | + } | ||
| 1474 | + | ||
| 1475 | + int EVPKeyPointer::id() const { | ||
| 1476 | + return id(get()); | ||
| 1477 | + } | ||
| 1478 | + | ||
| 1479 | + int EVPKeyPointer::base_id() const { | ||
| 1480 | + return base_id(get()); | ||
| 1481 | + } | ||
| 1482 | + | ||
| 1483 | + int EVPKeyPointer::bits() const { | ||
| 1484 | + if (get() == nullptr) return 0; | ||
| 1485 | + return EVP_PKEY_bits(get()); | ||
| 1486 | + } | ||
| 1487 | + | ||
| 1488 | + size_t EVPKeyPointer::size() const { | ||
| 1489 | + if (get() == nullptr) return 0; | ||
| 1490 | + return EVP_PKEY_size(get()); | ||
| 1491 | + } | ||
| 1492 | + | ||
| 1493 | + EVPKeyCtxPointer EVPKeyPointer::newCtx() const { | ||
| 1494 | + if (!pkey_) return {}; | ||
| 1495 | + return EVPKeyCtxPointer(EVP_PKEY_CTX_new(get(), nullptr)); | ||
| 1496 | + } | ||
| 1497 | + | ||
| 1498 | + size_t EVPKeyPointer::rawPublicKeySize() const { | ||
| 1499 | + if (!pkey_) return 0; | ||
| 1500 | + size_t len = 0; | ||
| 1501 | + if (EVP_PKEY_get_raw_public_key(get(), nullptr, &len) == 1) return len; | ||
| 1502 | + return 0; | ||
| 1503 | + } | ||
| 1504 | + | ||
| 1505 | + size_t EVPKeyPointer::rawPrivateKeySize() const { | ||
| 1506 | + if (!pkey_) return 0; | ||
| 1507 | + size_t len = 0; | ||
| 1508 | + if (EVP_PKEY_get_raw_private_key(get(), nullptr, &len) == 1) return len; | ||
| 1509 | + return 0; | ||
| 1510 | + } | ||
| 1511 | + | ||
| 1512 | + DataPointer EVPKeyPointer::rawPublicKey() const { | ||
| 1513 | + if (!pkey_) return {}; | ||
| 1514 | + if (auto data = DataPointer::Alloc(rawPublicKeySize())) { | ||
| 1515 | + const Buffer<unsigned char> buf = data; | ||
| 1516 | + size_t len = data.size(); | ||
| 1517 | + if (EVP_PKEY_get_raw_public_key(get(), | ||
| 1518 | + buf.data, | ||
| 1519 | + &len) != 1) return {}; | ||
| 1520 | + return data; | ||
| 1521 | + } | ||
| 1522 | + return {}; | ||
| 1523 | + } | ||
| 1524 | + | ||
| 1525 | + DataPointer EVPKeyPointer::rawPrivateKey() const { | ||
| 1526 | + if (!pkey_) return {}; | ||
| 1527 | + if (auto data = DataPointer::Alloc(rawPrivateKeySize())) { | ||
| 1528 | + const Buffer<unsigned char> buf = data; | ||
| 1529 | + size_t len = data.size(); | ||
| 1530 | + if (EVP_PKEY_get_raw_private_key(get(), | ||
| 1531 | + buf.data, | ||
| 1532 | + &len) != 1) return {}; | ||
| 1533 | + return data; | ||
| 1534 | + } | ||
| 1535 | + return {}; | ||
| 1536 | + } | ||
| 1537 | + | ||
| 1538 | + BIOPointer EVPKeyPointer::derPublicKey() const { | ||
| 1539 | + if (!pkey_) return {}; | ||
| 1540 | + auto bio = BIOPointer::NewMem(); | ||
| 1541 | + if (!bio) return {}; | ||
| 1542 | + if (!i2d_PUBKEY_bio(bio.get(), get())) return {}; | ||
| 1543 | + return bio; | ||
| 1544 | + } | ||
| 1545 | + | ||
| 1546 | + namespace { | ||
| 1547 | + EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner( | ||
| 1548 | + const BIOPointer& bp, | ||
| 1549 | + const char* name, | ||
| 1550 | + auto&& parse) { | ||
| 1551 | + if (!bp.resetBio()) { | ||
| 1552 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED); | ||
| 1553 | + } | ||
| 1554 | + unsigned char* der_data; | ||
| 1555 | + long der_len; | ||
| 1556 | + | ||
| 1557 | + // This skips surrounding data and decodes PEM to DER. | ||
| 1558 | + { | ||
| 1559 | + MarkPopErrorOnReturn mark_pop_error_on_return; | ||
| 1560 | + if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name, | ||
| 1561 | + bp.get(), nullptr, nullptr) != 1) | ||
| 1562 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED); | ||
| 1563 | + } | ||
| 1564 | + DataPointer data(der_data, der_len); | ||
| 1565 | + | ||
| 1566 | + // OpenSSL might modify the pointer, so we need to make a copy before parsing. | ||
| 1567 | + const unsigned char* p = der_data; | ||
| 1568 | + EVPKeyPointer pkey(parse(&p, der_len)); | ||
| 1569 | + if (!pkey) return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED); | ||
| 1570 | + return EVPKeyPointer::ParseKeyResult(std::move(pkey)); | ||
| 1571 | + } | ||
| 1572 | + | ||
| 1573 | + EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM( | ||
| 1574 | + const Buffer<const unsigned char>& buffer) { | ||
| 1575 | + auto bp = BIOPointer::New(buffer.data, buffer.len); | ||
| 1576 | + if (!bp) | ||
| 1577 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED); | ||
| 1578 | + | ||
| 1579 | + // Try parsing as SubjectPublicKeyInfo (SPKI) first. | ||
| 1580 | + if (auto ret = TryParsePublicKeyInner(bp, "PUBLIC KEY", | ||
| 1581 | + [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||
| 1582 | + return d2i_PUBKEY(nullptr, p, l); | ||
| 1583 | + })) { | ||
| 1584 | + return ret; | ||
| 1585 | + } | ||
| 1586 | + | ||
| 1587 | + // Maybe it is PKCS#1. | ||
| 1588 | + if (auto ret = TryParsePublicKeyInner(bp, "RSA PUBLIC KEY", | ||
| 1589 | + [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||
| 1590 | + return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l); | ||
| 1591 | + })) { | ||
| 1592 | + return ret; | ||
| 1593 | + } | ||
| 1594 | + | ||
| 1595 | + // X.509 fallback. | ||
| 1596 | + if (auto ret = TryParsePublicKeyInner(bp, "CERTIFICATE", | ||
| 1597 | + [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||
| 1598 | + X509Pointer x509(d2i_X509(nullptr, p, l)); | ||
| 1599 | + return x509 ? X509_get_pubkey(x509.get()) : nullptr; | ||
| 1600 | + })) { | ||
| 1601 | + return ret; | ||
| 1602 | + }; | ||
| 1603 | + | ||
| 1604 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED); | ||
| 1605 | + } | ||
| 1606 | + } // namespace | ||
| 1607 | + | ||
| 1608 | + EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey( | ||
| 1609 | + PKFormatType format, | ||
| 1610 | + PKEncodingType encoding, | ||
| 1611 | + const Buffer<const unsigned char>& buffer) { | ||
| 1612 | + if (format == PKFormatType::PEM) { | ||
| 1613 | + return TryParsePublicKeyPEM(buffer); | ||
| 1614 | + } | ||
| 1615 | + | ||
| 1616 | + if (format != PKFormatType::DER) { | ||
| 1617 | + return ParseKeyResult(PKParseError::FAILED); | ||
| 1618 | + } | ||
| 1619 | + | ||
| 1620 | + const unsigned char* start = buffer.data; | ||
| 1621 | + | ||
| 1622 | + EVP_PKEY* key = nullptr; | ||
| 1623 | + | ||
| 1624 | + if (encoding == PKEncodingType::PKCS1 && | ||
| 1625 | + (key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &start, buffer.len))) { | ||
| 1626 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key)); | ||
| 1627 | + } | ||
| 1628 | + | ||
| 1629 | + if (encoding == PKEncodingType::SPKI && | ||
| 1630 | + (key = d2i_PUBKEY(nullptr, &start, buffer.len))) { | ||
| 1631 | + return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key)); | ||
| 1632 | + } | ||
| 1633 | + | ||
| 1634 | + return ParseKeyResult(PKParseError::FAILED); | ||
| 1635 | + } | ||
| 1636 | + | ||
| 1428 | 1637 | } // namespace ncrypto | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -172,12 +172,16 @@ class MarkPopErrorOnReturn final { | |||
| 172 | 172 | CryptoErrorList* errors_; | |
| 173 | 173 | }; | |
| 174 | 174 | ||
| 175 | + // TODO(@jasnell): Eventually replace with std::expected when we are able to | ||
| 176 | + // bump up to c++23. | ||
| 175 | 177 | template <typename T, typename E> | |
| 176 | 178 | struct Result final { | |
| 179 | + const bool has_value; | ||
| 177 | 180 | T value; | |
| 178 | 181 | std::optional<E> error; | |
| 179 | - Result(T&& value) : value(std::move(value)) {} | ||
| 180 | - Result(E&& error) : error(std::move(error)) {} | ||
| 182 | + Result(T&& value) : has_value(true), value(std::move(value)) {} | ||
| 183 | + Result(E&& error) : has_value(false), error(std::move(error)) {} | ||
| 184 | + inline operator bool() const { return has_value; } | ||
| 181 | 185 | }; | |
| 182 | 186 | ||
| 183 | 187 | // ============================================================================ | |
@@ -202,7 +206,6 @@ using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>; | |||
| 202 | 206 | using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; | |
| 203 | 207 | using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>; | |
| 204 | 208 | using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>; | |
| 205 | - using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>; | ||
| 206 | 209 | using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>; | |
| 207 | 210 | using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>; | |
| 208 | 211 | using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>; | |
@@ -252,9 +255,10 @@ class DataPointer final { | |||
| 252 | 255 | Buffer<void> release(); | |
| 253 | 256 | ||
| 254 | 257 | // Returns a Buffer struct that is a view of the underlying data. | |
| 255 | - inline operator const Buffer<void>() const { | ||
| 258 | + template <typename T = void> | ||
| 259 | + inline operator const Buffer<T>() const { | ||
| 256 | 260 | return { | |
| 257 | - .data = data_, | ||
| 261 | + .data = static_cast<T*>(data_), | ||
| 258 | 262 | .len = len_, | |
| 259 | 263 | }; | |
| 260 | 264 | } | |
@@ -359,6 +363,75 @@ class BignumPointer final { | |||
| 359 | 363 | DeleteFnPtr<BIGNUM, BN_clear_free> bn_; | |
| 360 | 364 | }; | |
| 361 | 365 | ||
| 366 | + class EVPKeyPointer final { | ||
| 367 | + public: | ||
| 368 | + static EVPKeyPointer New(); | ||
| 369 | + static EVPKeyPointer NewRawPublic(int id, const Buffer<const unsigned char>& data); | ||
| 370 | + static EVPKeyPointer NewRawPrivate(int id, const Buffer<const unsigned char>& data); | ||
| 371 | + | ||
| 372 | + enum class PKEncodingType { | ||
| 373 | + // RSAPublicKey / RSAPrivateKey according to PKCS#1. | ||
| 374 | + PKCS1, | ||
| 375 | + // PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8. | ||
| 376 | + PKCS8, | ||
| 377 | + // SubjectPublicKeyInfo according to X.509. | ||
| 378 | + SPKI, | ||
| 379 | + // ECPrivateKey according to SEC1. | ||
| 380 | + SEC1 | ||
| 381 | + }; | ||
| 382 | + | ||
| 383 | + enum class PKFormatType { | ||
| 384 | + DER, | ||
| 385 | + PEM, | ||
| 386 | + JWK | ||
| 387 | + }; | ||
| 388 | + | ||
| 389 | + enum class PKParseError { | ||
| 390 | + NOT_RECOGNIZED, | ||
| 391 | + NEED_PASSPHRASE, | ||
| 392 | + FAILED | ||
| 393 | + }; | ||
| 394 | + using ParseKeyResult = Result<EVPKeyPointer, PKParseError>; | ||
| 395 | + | ||
| 396 | + static ParseKeyResult TryParsePublicKey( | ||
| 397 | + PKFormatType format, | ||
| 398 | + PKEncodingType encoding, | ||
| 399 | + const Buffer<const unsigned char>& buffer); | ||
| 400 | + | ||
| 401 | + EVPKeyPointer() = default; | ||
| 402 | + explicit EVPKeyPointer(EVP_PKEY* pkey); | ||
| 403 | + EVPKeyPointer(EVPKeyPointer&& other) noexcept; | ||
| 404 | + EVPKeyPointer& operator=(EVPKeyPointer&& other) noexcept; | ||
| 405 | + NCRYPTO_DISALLOW_COPY(EVPKeyPointer) | ||
| 406 | + ~EVPKeyPointer(); | ||
| 407 | + | ||
| 408 | + inline bool operator==(std::nullptr_t) const noexcept { return pkey_ == nullptr; } | ||
| 409 | + inline operator bool() const { return pkey_ != nullptr; } | ||
| 410 | + inline EVP_PKEY* get() const { return pkey_.get(); } | ||
| 411 | + void reset(EVP_PKEY* pkey = nullptr); | ||
| 412 | + EVP_PKEY* release(); | ||
| 413 | + | ||
| 414 | + static int id(const EVP_PKEY* key); | ||
| 415 | + static int base_id(const EVP_PKEY* key); | ||
| 416 | + | ||
| 417 | + int id() const; | ||
| 418 | + int base_id() const; | ||
| 419 | + int bits() const; | ||
| 420 | + size_t size() const; | ||
| 421 | + | ||
| 422 | + size_t rawPublicKeySize() const; | ||
| 423 | + size_t rawPrivateKeySize() const; | ||
| 424 | + DataPointer rawPublicKey() const; | ||
| 425 | + DataPointer rawPrivateKey() const; | ||
| 426 | + | ||
| 427 | + BIOPointer derPublicKey() const; | ||
| 428 | + | ||
| 429 | + EVPKeyCtxPointer newCtx() const; | ||
| 430 | + | ||
| 431 | + private: | ||
| 432 | + DeleteFnPtr<EVP_PKEY, EVP_PKEY_free> pkey_; | ||
| 433 | + }; | ||
| 434 | + | ||
| 362 | 435 | class DHPointer final { | |
| 363 | 436 | public: | |
| 364 | 437 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -996,7 +996,7 @@ bool PublicKeyCipher::Cipher( | |||
| 996 | 996 | const ArrayBufferOrViewContents<unsigned char>& oaep_label, | |
| 997 | 997 | const ArrayBufferOrViewContents<unsigned char>& data, | |
| 998 | 998 | std::unique_ptr<BackingStore>* out) { | |
| 999 | - EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); | ||
| 999 | + EVPKeyCtxPointer ctx = pkey.newCtx(); | ||
| 1000 | 1000 | if (!ctx) | |
| 1001 | 1001 | return false; | |
| 1002 | 1002 | if (EVP_PKEY_cipher_init(ctx.get()) <= 0) | |
@@ -1072,7 +1072,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) { | |||
| 1072 | 1072 | ||
| 1073 | 1073 | if (EVP_PKEY_cipher == EVP_PKEY_decrypt && | |
| 1074 | 1074 | operation == PublicKeyCipher::kPrivate && padding == RSA_PKCS1_PADDING) { | |
| 1075 | - EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); | ||
| 1075 | + EVPKeyCtxPointer ctx = pkey.newCtx(); | ||
| 1076 | 1076 | CHECK(ctx); | |
| 1077 | 1077 | ||
| 1078 | 1078 | if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -449,15 +449,14 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) { | |||
| 449 | 449 | Local<Context> context = env->context(); | |
| 450 | 450 | crypto::EVPKeyPointer key(raw_key); | |
| 451 | 451 | ||
| 452 | - int kid = EVP_PKEY_id(key.get()); | ||
| 453 | - int bits = EVP_PKEY_bits(key.get()); | ||
| 452 | + int kid = key.id(); | ||
| 454 | 453 | switch (kid) { | |
| 455 | 454 | case EVP_PKEY_DH: | |
| 456 | 455 | if (!Set<String>(context, info, env->type_string(), env->dh_string()) || | |
| 457 | 456 | !Set<Integer>(context, | |
| 458 | - info, | ||
| 459 | - env->size_string(), | ||
| 460 | - Integer::New(env->isolate(), bits))) { | ||
| 457 | + info, | ||
| 458 | + env->size_string(), | ||
| 459 | + Integer::New(env->isolate(), key.bits()))) { | ||
| 461 | 460 | return MaybeLocal<Object>(); | |
| 462 | 461 | } | |
| 463 | 462 | break; | |
@@ -473,18 +472,16 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) { | |||
| 473 | 472 | } else { | |
| 474 | 473 | curve_name = OBJ_nid2sn(kid); | |
| 475 | 474 | } | |
| 476 | - if (!Set<String>(context, | ||
| 477 | - info, | ||
| 478 | - env->type_string(), | ||
| 479 | - env->ecdh_string()) || | ||
| 475 | + if (!Set<String>( | ||
| 476 | + context, info, env->type_string(), env->ecdh_string()) || | ||
| 480 | 477 | !Set<String>(context, | |
| 481 | - info, | ||
| 482 | - env->name_string(), | ||
| 483 | - OneByteString(env->isolate(), curve_name)) || | ||
| 478 | + info, | ||
| 479 | + env->name_string(), | ||
| 480 | + OneByteString(env->isolate(), curve_name)) || | ||
| 484 | 481 | !Set<Integer>(context, | |
| 485 | - info, | ||
| 486 | - env->size_string(), | ||
| 487 | - Integer::New(env->isolate(), bits))) { | ||
| 482 | + info, | ||
| 483 | + env->size_string(), | ||
| 484 | + Integer::New(env->isolate(), key.bits()))) { | ||
| 488 | 485 | return MaybeLocal<Object>(); | |
| 489 | 486 | } | |
| 490 | 487 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments