| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -368,41 +368,83 @@ notify_ssl_error_occurred(void) | |||
| 368 | 368 | } | |
| 369 | 369 | /* LCOV_EXCL_STOP */ | |
| 370 | 370 | ||
| 371 | - static const char * | ||
| 372 | - get_openssl_evp_md_utf8name(const EVP_MD *md) | ||
| 373 | - { | ||
| 374 | - assert(md != NULL); | ||
| 375 | - int nid = EVP_MD_nid(md); | ||
| 376 | - const char *name = NULL; | ||
| 377 | - const py_hashentry_t *h; | ||
| 371 | + /* | ||
| 372 | + * OpenSSL provides a way to go from NIDs to digest names for hash functions | ||
| 373 | + * but lacks this granularity for MAC objects where it is not possible to get | ||
| 374 | + * the underlying digest name (only the block size and digest size are allowed | ||
| 375 | + * to be recovered). | ||
| 376 | + * | ||
| 377 | + * In addition, OpenSSL aliases pollute the list of known digest names | ||
| 378 | + * as OpenSSL appears to have its own definition of alias. In particular, | ||
| 379 | + * the resulting list still contains duplicate and alternate names for several | ||
| 380 | + * algorithms. | ||
| 381 | + * | ||
| 382 | + * Therefore, digest names, whether they are used by hash functions or HMAC, | ||
| 383 | + * are handled through EVP_MD objects or directly by using some NID. | ||
| 384 | + */ | ||
| 378 | 385 | ||
| 379 | - for (h = py_hashes; h->py_name != NULL; h++) { | ||
| 386 | + /* Get a cached entry by OpenSSL NID. */ | ||
| 387 | + static const py_hashentry_t * | ||
| 388 | + get_hashentry_by_nid(int nid) | ||
| 389 | + { | ||
| 390 | + for (const py_hashentry_t *h = py_hashes; h->py_name != NULL; h++) { | ||
| 380 | 391 | if (h->ossl_nid == nid) { | |
| 381 | - name = h->py_name; | ||
| 382 | - break; | ||
| 392 | + return h; | ||
| 383 | 393 | } | |
| 384 | 394 | } | |
| 395 | + return NULL; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + /* | ||
| 399 | + * Convert the NID to a string via OBJ_nid2_*() functions. | ||
| 400 | + * | ||
| 401 | + * If 'nid' cannot be resolved, set an exception and return NULL. | ||
| 402 | + */ | ||
| 403 | + static const char * | ||
| 404 | + get_asn1_utf8name_by_nid(int nid) | ||
| 405 | + { | ||
| 406 | + const char *name = OBJ_nid2ln(nid); | ||
| 385 | 407 | if (name == NULL) { | |
| 386 | - /* Ignore aliased names and only use long, lowercase name. The aliases | ||
| 387 | - * pollute the list and OpenSSL appears to have its own definition of | ||
| 388 | - * alias as the resulting list still contains duplicate and alternate | ||
| 389 | - * names for several algorithms. | ||
| 390 | - */ | ||
| 391 | - name = OBJ_nid2ln(nid); | ||
| 392 | - if (name == NULL) | ||
| 393 | - name = OBJ_nid2sn(nid); | ||
| 408 | + // In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise. | ||
| 409 | + assert(ERR_peek_last_error() != 0); | ||
| 410 | + if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) { | ||
| 411 | + notify_ssl_error_occurred(); | ||
| 412 | + return NULL; | ||
| 413 | + } | ||
| 414 | + // fallback to short name and unconditionally propagate errors | ||
| 415 | + name = OBJ_nid2sn(nid); | ||
| 416 | + if (name == NULL) { | ||
| 417 | + raise_ssl_error(PyExc_ValueError, "cannot resolve NID %d", nid); | ||
| 418 | + } | ||
| 394 | 419 | } | |
| 395 | 420 | return name; | |
| 396 | 421 | } | |
| 397 | 422 | ||
| 398 | - static PyObject * | ||
| 399 | - get_openssl_evp_md_name(const EVP_MD *md) | ||
| 423 | + /* | ||
| 424 | + * Convert the NID to an OpenSSL digest name. | ||
| 425 | + * | ||
| 426 | + * On error, set an exception and return NULL. | ||
| 427 | + */ | ||
| 428 | + static const char * | ||
| 429 | + get_hashlib_utf8name_by_nid(int nid) | ||
| 430 | + { | ||
| 431 | + const py_hashentry_t *e = get_hashentry_by_nid(nid); | ||
| 432 | + return e ? e->py_name : get_asn1_utf8name_by_nid(nid); | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | + /* Same as get_hashlib_utf8name_by_nid() but using an EVP_MD object. */ | ||
| 436 | + static const char * | ||
| 437 | + get_hashlib_utf8name_by_evp_md(const EVP_MD *md) | ||
| 400 | 438 | { | |
| 401 | - const char *name = get_openssl_evp_md_utf8name(md); | ||
| 402 | - return PyUnicode_FromString(name); | ||
| 439 | + assert(md != NULL); | ||
| 440 | + return get_hashlib_utf8name_by_nid(EVP_MD_nid(md)); | ||
| 403 | 441 | } | |
| 404 | 442 | ||
| 405 | - /* Get EVP_MD by HID and purpose */ | ||
| 443 | + /* | ||
| 444 | + * Get a new reference to an EVP_MD object described by name and purpose. | ||
| 445 | + * | ||
| 446 | + * If 'name' is an OpenSSL indexed name, the return value is cached. | ||
| 447 | + */ | ||
| 406 | 448 | static PY_EVP_MD * | |
| 407 | 449 | get_openssl_evp_md_by_utf8name(PyObject *module, const char *name, | |
| 408 | 450 | Py_hash_type py_ht) | |
@@ -464,49 +506,54 @@ get_openssl_evp_md_by_utf8name(PyObject *module, const char *name, | |||
| 464 | 506 | } | |
| 465 | 507 | } | |
| 466 | 508 | if (digest == NULL) { | |
| 509 | + // NOTE(picnixz): report hash type value instead of name | ||
| 467 | 510 | raise_ssl_error(state->unsupported_digestmod_error, | |
| 468 | 511 | "unsupported hash type %s", name); | |
| 469 | 512 | return NULL; | |
| 470 | 513 | } | |
| 471 | 514 | return digest; | |
| 472 | 515 | } | |
| 473 | 516 | ||
| 474 | - /* Get digest EVP_MD from object | ||
| 517 | + /* | ||
| 518 | + * Raise an exception indicating that 'digestmod' is not supported. | ||
| 519 | + */ | ||
| 520 | + static void | ||
| 521 | + raise_unsupported_digestmod_error(PyObject *module, PyObject *digestmod) | ||
| 522 | + { | ||
| 523 | + _hashlibstate *state = get_hashlib_state(module); | ||
| 524 | + PyErr_Format(state->unsupported_digestmod_error, | ||
| 525 | + "Unsupported digestmod %R", digestmod); | ||
| 526 | + } | ||
| 527 | + | ||
| 528 | + /* | ||
| 529 | + * Get a new reference to an EVP_MD described by 'digestmod' and purpose. | ||
| 530 | + * | ||
| 531 | + * On error, set an exception and return NULL. | ||
| 475 | 532 | * | |
| 476 | - * * string | ||
| 477 | - * * _hashopenssl builtin function | ||
| 533 | + * Parameters | ||
| 478 | 534 | * | |
| 479 | - * on error returns NULL with exception set. | ||
| 535 | + * digestmod A digest name or a _hashlib.openssl_* function | ||
| 536 | + * py_ht The message digest purpose. | ||
| 480 | 537 | */ | |
| 481 | 538 | static PY_EVP_MD * | |
| 482 | - get_openssl_evp_md(PyObject *module, PyObject *digestmod, | ||
| 483 | - Py_hash_type py_ht) | ||
| 539 | + get_openssl_evp_md(PyObject *module, PyObject *digestmod, Py_hash_type py_ht) | ||
| 484 | 540 | { | |
| 485 | - PyObject *name_obj = NULL; | ||
| 486 | 541 | const char *name; | |
| 487 | - | ||
| 488 | 542 | if (PyUnicode_Check(digestmod)) { | |
| 489 | - name_obj = digestmod; | ||
| 490 | - } else { | ||
| 491 | - _hashlibstate *state = get_hashlib_state(module); | ||
| 492 | - // borrowed ref | ||
| 493 | - name_obj = PyDict_GetItemWithError(state->constructs, digestmod); | ||
| 543 | + name = PyUnicode_AsUTF8(digestmod); | ||
| 494 | 544 | } | |
| 495 | - if (name_obj == NULL) { | ||
| 496 | - if (!PyErr_Occurred()) { | ||
| 497 | - _hashlibstate *state = get_hashlib_state(module); | ||
| 498 | - PyErr_Format( | ||
| 499 | - state->unsupported_digestmod_error, | ||
| 500 | - "Unsupported digestmod %R", digestmod); | ||
| 501 | - } | ||
| 502 | - return NULL; | ||
| 545 | + else { | ||
| 546 | + PyObject *dict = get_hashlib_state(module)->constructs; | ||
| 547 | + assert(dict != NULL); | ||
| 548 | + PyObject *borrowed_ref = PyDict_GetItemWithError(dict, digestmod); | ||
| 549 | + name = borrowed_ref == NULL ? NULL : PyUnicode_AsUTF8(borrowed_ref); | ||
| 503 | 550 | } | |
| 504 | - | ||
| 505 | - name = PyUnicode_AsUTF8(name_obj); | ||
| 506 | 551 | if (name == NULL) { | |
| 552 | + if (!PyErr_Occurred()) { | ||
| 553 | + raise_unsupported_digestmod_error(module, digestmod); | ||
| 554 | + } | ||
| 507 | 555 | return NULL; | |
| 508 | 556 | } | |
| 509 | - | ||
| 510 | 557 | return get_openssl_evp_md_by_utf8name(module, name, py_ht); | |
| 511 | 558 | } | |
| 512 | 559 | ||
@@ -745,7 +792,9 @@ _hashlib_HASH_get_name(PyObject *op, void *Py_UNUSED(closure)) | |||
| 745 | 792 | notify_ssl_error_occurred(); | |
| 746 | 793 | return NULL; | |
| 747 | 794 | } | |
| 748 | - return get_openssl_evp_md_name(md); | ||
| 795 | + const char *name = get_hashlib_utf8name_by_evp_md(md); | ||
| 796 | + assert(name != NULL || PyErr_Occurred()); | ||
| 797 | + return name == NULL ? NULL : PyUnicode_FromString(name); | ||
| 749 | 798 | } | |
| 750 | 799 | ||
| 751 | 800 | static PyGetSetDef HASH_getsets[] = { | |
@@ -1775,20 +1824,15 @@ _hmac_dealloc(PyObject *op) | |||
| 1775 | 1824 | static PyObject * | |
| 1776 | 1825 | _hmac_repr(PyObject *op) | |
| 1777 | 1826 | { | |
| 1827 | + const char *digest_name; | ||
| 1778 | 1828 | HMACobject *self = HMACobject_CAST(op); | |
| 1779 | 1829 | const EVP_MD *md = _hashlib_hmac_get_md(self); | |
| 1780 | - if (md == NULL) { | ||
| 1781 | - return NULL; | ||
| 1782 | - } | ||
| 1783 | - PyObject *digest_name = get_openssl_evp_md_name(md); | ||
| 1830 | + digest_name = md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md); | ||
| 1784 | 1831 | if (digest_name == NULL) { | |
| 1832 | + assert(PyErr_Occurred()); | ||
| 1785 | 1833 | return NULL; | |
| 1786 | 1834 | } | |
| 1787 | - PyObject *repr = PyUnicode_FromFormat( | ||
| 1788 | - "<%U HMAC object @ %p>", digest_name, self | ||
| 1789 | - ); | ||
| 1790 | - Py_DECREF(digest_name); | ||
| 1791 | - return repr; | ||
| 1835 | + return PyUnicode_FromFormat("<%s HMAC object @ %p>", digest_name, self); | ||
| 1792 | 1836 | } | |
| 1793 | 1837 | ||
| 1794 | 1838 | /*[clinic input] | |
@@ -1900,13 +1944,12 @@ _hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure)) | |||
| 1900 | 1944 | if (md == NULL) { | |
| 1901 | 1945 | return NULL; | |
| 1902 | 1946 | } | |
| 1903 | - PyObject *digest_name = get_openssl_evp_md_name(md); | ||
| 1947 | + const char *digest_name = get_hashlib_utf8name_by_evp_md(md); | ||
| 1904 | 1948 | if (digest_name == NULL) { | |
| 1949 | + assert(PyErr_Occurred()); | ||
| 1905 | 1950 | return NULL; | |
| 1906 | 1951 | } | |
| 1907 | - PyObject *name = PyUnicode_FromFormat("hmac-%U", digest_name); | ||
| 1908 | - Py_DECREF(digest_name); | ||
| 1909 | - return name; | ||
| 1952 | + return PyUnicode_FromFormat("hmac-%s", digest_name); | ||
| 1910 | 1953 | } | |
| 1911 | 1954 | ||
| 1912 | 1955 | static PyMethodDef HMAC_methods[] = { | |
@@ -1982,7 +2025,9 @@ _openssl_hash_name_mapper(const EVP_MD *md, const char *from, | |||
| 1982 | 2025 | return; | |
| 1983 | 2026 | } | |
| 1984 | 2027 | ||
| 1985 | - py_name = get_openssl_evp_md_name(md); | ||
| 2028 | + const char *name = get_hashlib_utf8name_by_evp_md(md); | ||
| 2029 | + assert(name != NULL || PyErr_Occurred()); | ||
| 2030 | + py_name = name == NULL ? NULL : PyUnicode_FromString(name); | ||
| 1986 | 2031 | if (py_name == NULL) { | |
| 1987 | 2032 | state->error = 1; | |
| 1988 | 2033 | } else { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments