From c3edc19afcfc3cfa9abafc7823ac7748d8f0ecaf Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 18 Jan 2015 17:39:32 +0100 Subject: Issue #23248: Update ssl error codes from latest OpenSSL git master. --- Misc/NEWS | 2 + Modules/_ssl_data.h | 297 ++++++++++++++++++++++++++++++++++++++++++++- Tools/ssl/make_ssl_data.py | 57 ++++++--- 3 files changed, 336 insertions(+), 20 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index c84af7b..faf704a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,8 @@ Core and Builtins Library ------- +- Issue #23248: Update ssl error codes from latest OpenSSL git master. + - Issue #23098: 64-bit dev_t is now supported in the os module. - Issue #23063: In the disutils' check command, fix parsing of reST with code or diff --git a/Modules/_ssl_data.h b/Modules/_ssl_data.h index 81a8d7b..85165b9 100644 --- a/Modules/_ssl_data.h +++ b/Modules/_ssl_data.h @@ -1,5 +1,5 @@ /* File generated by Tools/ssl/make_ssl_data.py */ -/* Generated on 2012-05-16T23:56:40.981382 */ +/* Generated on 2015-01-17T20:33:43.377453 */ static struct py_ssl_library_code library_codes[] = { {"PEM", ERR_LIB_PEM}, @@ -179,6 +179,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"BAD_CHECKSUM", ERR_LIB_SSL, 104}, #endif + #ifdef SSL_R_BAD_DATA + {"BAD_DATA", ERR_LIB_SSL, SSL_R_BAD_DATA}, + #else + {"BAD_DATA", ERR_LIB_SSL, 390}, + #endif #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, #else @@ -309,6 +314,46 @@ static struct py_ssl_error_code error_codes[] = { #else {"BAD_SIGNATURE", ERR_LIB_SSL, 123}, #endif + #ifdef SSL_R_BAD_SRP_A_LENGTH + {"BAD_SRP_A_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_A_LENGTH}, + #else + {"BAD_SRP_A_LENGTH", ERR_LIB_SSL, 347}, + #endif + #ifdef SSL_R_BAD_SRP_B_LENGTH + {"BAD_SRP_B_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_B_LENGTH}, + #else + {"BAD_SRP_B_LENGTH", ERR_LIB_SSL, 348}, + #endif + #ifdef SSL_R_BAD_SRP_G_LENGTH + {"BAD_SRP_G_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_G_LENGTH}, + #else + {"BAD_SRP_G_LENGTH", ERR_LIB_SSL, 349}, + #endif + #ifdef SSL_R_BAD_SRP_N_LENGTH + {"BAD_SRP_N_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_N_LENGTH}, + #else + {"BAD_SRP_N_LENGTH", ERR_LIB_SSL, 350}, + #endif + #ifdef SSL_R_BAD_SRP_PARAMETERS + {"BAD_SRP_PARAMETERS", ERR_LIB_SSL, SSL_R_BAD_SRP_PARAMETERS}, + #else + {"BAD_SRP_PARAMETERS", ERR_LIB_SSL, 371}, + #endif + #ifdef SSL_R_BAD_SRP_S_LENGTH + {"BAD_SRP_S_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_S_LENGTH}, + #else + {"BAD_SRP_S_LENGTH", ERR_LIB_SSL, 351}, + #endif + #ifdef SSL_R_BAD_SRTP_MKI_VALUE + {"BAD_SRTP_MKI_VALUE", ERR_LIB_SSL, SSL_R_BAD_SRTP_MKI_VALUE}, + #else + {"BAD_SRTP_MKI_VALUE", ERR_LIB_SSL, 352}, + #endif + #ifdef SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST + {"BAD_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST}, + #else + {"BAD_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, 353}, + #endif #ifdef SSL_R_BAD_SSL_FILETYPE {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, #else @@ -324,6 +369,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"BAD_STATE", ERR_LIB_SSL, 126}, #endif + #ifdef SSL_R_BAD_VALUE + {"BAD_VALUE", ERR_LIB_SSL, SSL_R_BAD_VALUE}, + #else + {"BAD_VALUE", ERR_LIB_SSL, 384}, + #endif #ifdef SSL_R_BAD_WRITE_RETRY {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, #else @@ -354,6 +404,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"CA_DN_TOO_LONG", ERR_LIB_SSL, 132}, #endif + #ifdef SSL_R_CA_KEY_TOO_SMALL + {"CA_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_CA_KEY_TOO_SMALL}, + #else + {"CA_KEY_TOO_SMALL", ERR_LIB_SSL, 397}, + #endif + #ifdef SSL_R_CA_MD_TOO_WEAK + {"CA_MD_TOO_WEAK", ERR_LIB_SSL, SSL_R_CA_MD_TOO_WEAK}, + #else + {"CA_MD_TOO_WEAK", ERR_LIB_SSL, 398}, + #endif #ifdef SSL_R_CCS_RECEIVED_EARLY {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, #else @@ -364,6 +424,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, 134}, #endif + #ifdef SSL_R_CERT_CB_ERROR + {"CERT_CB_ERROR", ERR_LIB_SSL, SSL_R_CERT_CB_ERROR}, + #else + {"CERT_CB_ERROR", ERR_LIB_SSL, 377}, + #endif #ifdef SSL_R_CERT_LENGTH_MISMATCH {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, #else @@ -454,6 +519,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, 281}, #endif + #ifdef SSL_R_DH_KEY_TOO_SMALL + {"DH_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL}, + #else + {"DH_KEY_TOO_SMALL", ERR_LIB_SSL, 394}, + #endif #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, #else @@ -494,11 +564,26 @@ static struct py_ssl_error_code error_codes[] = { #else {"ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE", ERR_LIB_SSL, 323}, #endif + #ifdef SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE + {"ECDH_REQUIRED_FOR_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE}, + #else + {"ECDH_REQUIRED_FOR_SUITEB_MODE", ERR_LIB_SSL, 374}, + #endif #ifdef SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER}, #else {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, 310}, #endif + #ifdef SSL_R_EE_KEY_TOO_SMALL + {"EE_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_EE_KEY_TOO_SMALL}, + #else + {"EE_KEY_TOO_SMALL", ERR_LIB_SSL, 399}, + #endif + #ifdef SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST + {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST}, + #else + {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, 354}, + #endif #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, #else @@ -529,6 +614,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, 154}, #endif + #ifdef SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS + {"GOT_NEXT_PROTO_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS}, + #else + {"GOT_NEXT_PROTO_BEFORE_A_CCS", ERR_LIB_SSL, 355}, + #endif + #ifdef SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION + {"GOT_NEXT_PROTO_WITHOUT_EXTENSION", ERR_LIB_SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION}, + #else + {"GOT_NEXT_PROTO_WITHOUT_EXTENSION", ERR_LIB_SSL, 356}, + #endif #ifdef SSL_R_HTTPS_PROXY_REQUEST {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, #else @@ -544,6 +639,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"ILLEGAL_PADDING", ERR_LIB_SSL, 283}, #endif + #ifdef SSL_R_ILLEGAL_SUITEB_DIGEST + {"ILLEGAL_SUITEB_DIGEST", ERR_LIB_SSL, SSL_R_ILLEGAL_SUITEB_DIGEST}, + #else + {"ILLEGAL_SUITEB_DIGEST", ERR_LIB_SSL, 380}, + #endif + #ifdef SSL_R_INAPPROPRIATE_FALLBACK + {"INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_INAPPROPRIATE_FALLBACK}, + #else + {"INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, 373}, + #endif #ifdef SSL_R_INCONSISTENT_COMPRESSION {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, #else @@ -564,11 +669,26 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, 341}, #endif + #ifdef SSL_R_INVALID_NULL_CMD_NAME + {"INVALID_NULL_CMD_NAME", ERR_LIB_SSL, SSL_R_INVALID_NULL_CMD_NAME}, + #else + {"INVALID_NULL_CMD_NAME", ERR_LIB_SSL, 385}, + #endif #ifdef SSL_R_INVALID_PURPOSE {"INVALID_PURPOSE", ERR_LIB_SSL, SSL_R_INVALID_PURPOSE}, #else {"INVALID_PURPOSE", ERR_LIB_SSL, 278}, #endif + #ifdef SSL_R_INVALID_SERVERINFO_DATA + {"INVALID_SERVERINFO_DATA", ERR_LIB_SSL, SSL_R_INVALID_SERVERINFO_DATA}, + #else + {"INVALID_SERVERINFO_DATA", ERR_LIB_SSL, 388}, + #endif + #ifdef SSL_R_INVALID_SRP_USERNAME + {"INVALID_SRP_USERNAME", ERR_LIB_SSL, SSL_R_INVALID_SRP_USERNAME}, + #else + {"INVALID_SRP_USERNAME", ERR_LIB_SSL, 357}, + #endif #ifdef SSL_R_INVALID_STATUS_RESPONSE {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, #else @@ -689,6 +809,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, 165}, #endif + #ifdef SSL_R_MISSING_ECDH_CERT + {"MISSING_ECDH_CERT", ERR_LIB_SSL, SSL_R_MISSING_ECDH_CERT}, + #else + {"MISSING_ECDH_CERT", ERR_LIB_SSL, 382}, + #endif + #ifdef SSL_R_MISSING_ECDSA_SIGNING_CERT + {"MISSING_ECDSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_ECDSA_SIGNING_CERT}, + #else + {"MISSING_ECDSA_SIGNING_CERT", ERR_LIB_SSL, 381}, + #endif #ifdef SSL_R_MISSING_EXPORT_TMP_DH_KEY {"MISSING_EXPORT_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_EXPORT_TMP_DH_KEY}, #else @@ -714,6 +844,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, 170}, #endif + #ifdef SSL_R_MISSING_SRP_PARAM + {"MISSING_SRP_PARAM", ERR_LIB_SSL, SSL_R_MISSING_SRP_PARAM}, + #else + {"MISSING_SRP_PARAM", ERR_LIB_SSL, 358}, + #endif #ifdef SSL_R_MISSING_TMP_DH_KEY {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, #else @@ -739,6 +874,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_VERIFY_MESSAGE", ERR_LIB_SSL, 174}, #endif + #ifdef SSL_R_MULTIPLE_SGC_RESTARTS + {"MULTIPLE_SGC_RESTARTS", ERR_LIB_SSL, SSL_R_MULTIPLE_SGC_RESTARTS}, + #else + {"MULTIPLE_SGC_RESTARTS", ERR_LIB_SSL, 346}, + #endif #ifdef SSL_R_NON_SSLV2_INITIAL_PACKET {"NON_SSLV2_INITIAL_PACKET", ERR_LIB_SSL, SSL_R_NON_SSLV2_INITIAL_PACKET}, #else @@ -819,6 +959,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, 188}, #endif + #ifdef SSL_R_NO_PEM_EXTENSIONS + {"NO_PEM_EXTENSIONS", ERR_LIB_SSL, SSL_R_NO_PEM_EXTENSIONS}, + #else + {"NO_PEM_EXTENSIONS", ERR_LIB_SSL, 389}, + #endif #ifdef SSL_R_NO_PRIVATEKEY {"NO_PRIVATEKEY", ERR_LIB_SSL, SSL_R_NO_PRIVATEKEY}, #else @@ -854,6 +999,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"NO_SHARED_CIPHER", ERR_LIB_SSL, 193}, #endif + #ifdef SSL_R_NO_SHARED_SIGATURE_ALGORITHMS + {"NO_SHARED_SIGATURE_ALGORITHMS", ERR_LIB_SSL, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS}, + #else + {"NO_SHARED_SIGATURE_ALGORITHMS", ERR_LIB_SSL, 376}, + #endif + #ifdef SSL_R_NO_SRTP_PROFILES + {"NO_SRTP_PROFILES", ERR_LIB_SSL, SSL_R_NO_SRTP_PROFILES}, + #else + {"NO_SRTP_PROFILES", ERR_LIB_SSL, 359}, + #endif #ifdef SSL_R_NO_VERIFY_CALLBACK {"NO_VERIFY_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_CALLBACK}, #else @@ -879,6 +1034,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, 344}, #endif + #ifdef SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE + {"ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE}, + #else + {"ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE", ERR_LIB_SSL, 387}, + #endif + #ifdef SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE + {"ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE}, + #else + {"ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE", ERR_LIB_SSL, 379}, + #endif #ifdef SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE {"ONLY_TLS_ALLOWED_IN_FIPS_MODE", ERR_LIB_SSL, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE}, #else @@ -934,6 +1099,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE", ERR_LIB_SSL, 204}, #endif + #ifdef SSL_R_PEM_NAME_BAD_PREFIX + {"PEM_NAME_BAD_PREFIX", ERR_LIB_SSL, SSL_R_PEM_NAME_BAD_PREFIX}, + #else + {"PEM_NAME_BAD_PREFIX", ERR_LIB_SSL, 391}, + #endif + #ifdef SSL_R_PEM_NAME_TOO_SHORT + {"PEM_NAME_TOO_SHORT", ERR_LIB_SSL, SSL_R_PEM_NAME_TOO_SHORT}, + #else + {"PEM_NAME_TOO_SHORT", ERR_LIB_SSL, 392}, + #endif #ifdef SSL_R_PRE_MAC_LENGTH_TOO_LONG {"PRE_MAC_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PRE_MAC_LENGTH_TOO_LONG}, #else @@ -1069,11 +1244,36 @@ static struct py_ssl_error_code error_codes[] = { #else {"SHORT_READ", ERR_LIB_SSL, 219}, #endif + #ifdef SSL_R_SIGNATURE_ALGORITHMS_ERROR + {"SIGNATURE_ALGORITHMS_ERROR", ERR_LIB_SSL, SSL_R_SIGNATURE_ALGORITHMS_ERROR}, + #else + {"SIGNATURE_ALGORITHMS_ERROR", ERR_LIB_SSL, 360}, + #endif #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, #else {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, 220}, #endif + #ifdef SSL_R_SRP_A_CALC + {"SRP_A_CALC", ERR_LIB_SSL, SSL_R_SRP_A_CALC}, + #else + {"SRP_A_CALC", ERR_LIB_SSL, 361}, + #endif + #ifdef SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES + {"SRTP_COULD_NOT_ALLOCATE_PROFILES", ERR_LIB_SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES}, + #else + {"SRTP_COULD_NOT_ALLOCATE_PROFILES", ERR_LIB_SSL, 362}, + #endif + #ifdef SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG + {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", ERR_LIB_SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG}, + #else + {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", ERR_LIB_SSL, 363}, + #endif + #ifdef SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE + {"SRTP_UNKNOWN_PROTECTION_PROFILE", ERR_LIB_SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE}, + #else + {"SRTP_UNKNOWN_PROTECTION_PROFILE", ERR_LIB_SSL, 364}, + #endif #ifdef SSL_R_SSL23_DOING_SESSION_ID_REUSE {"SSL23_DOING_SESSION_ID_REUSE", ERR_LIB_SSL, SSL_R_SSL23_DOING_SESSION_ID_REUSE}, #else @@ -1179,6 +1379,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, 230}, #endif + #ifdef SSL_R_SSL_NEGATIVE_LENGTH + {"SSL_NEGATIVE_LENGTH", ERR_LIB_SSL, SSL_R_SSL_NEGATIVE_LENGTH}, + #else + {"SSL_NEGATIVE_LENGTH", ERR_LIB_SSL, 372}, + #endif #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, #else @@ -1229,6 +1434,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, 1060}, #endif + #ifdef SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK + {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK}, + #else + {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, 1086}, + #endif #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, #else @@ -1294,6 +1504,21 @@ static struct py_ssl_error_code error_codes[] = { #else {"TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER", ERR_LIB_SSL, 232}, #endif + #ifdef SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT + {"TLS_HEARTBEAT_PEER_DOESNT_ACCEPT", ERR_LIB_SSL, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT}, + #else + {"TLS_HEARTBEAT_PEER_DOESNT_ACCEPT", ERR_LIB_SSL, 365}, + #endif + #ifdef SSL_R_TLS_HEARTBEAT_PENDING + {"TLS_HEARTBEAT_PENDING", ERR_LIB_SSL, SSL_R_TLS_HEARTBEAT_PENDING}, + #else + {"TLS_HEARTBEAT_PENDING", ERR_LIB_SSL, 366}, + #endif + #ifdef SSL_R_TLS_ILLEGAL_EXPORTER_LABEL + {"TLS_ILLEGAL_EXPORTER_LABEL", ERR_LIB_SSL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL}, + #else + {"TLS_ILLEGAL_EXPORTER_LABEL", ERR_LIB_SSL, 367}, + #endif #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, #else @@ -1399,6 +1624,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, 249}, #endif + #ifdef SSL_R_UNKNOWN_CMD_NAME + {"UNKNOWN_CMD_NAME", ERR_LIB_SSL, SSL_R_UNKNOWN_CMD_NAME}, + #else + {"UNKNOWN_CMD_NAME", ERR_LIB_SSL, 386}, + #endif + #ifdef SSL_R_UNKNOWN_DIGEST + {"UNKNOWN_DIGEST", ERR_LIB_SSL, SSL_R_UNKNOWN_DIGEST}, + #else + {"UNKNOWN_DIGEST", ERR_LIB_SSL, 368}, + #endif #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, #else @@ -1469,16 +1704,36 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, 329}, #endif + #ifdef SSL_R_USE_SRTP_NOT_NEGOTIATED + {"USE_SRTP_NOT_NEGOTIATED", ERR_LIB_SSL, SSL_R_USE_SRTP_NOT_NEGOTIATED}, + #else + {"USE_SRTP_NOT_NEGOTIATED", ERR_LIB_SSL, 369}, + #endif + #ifdef SSL_R_VERSION_TOO_LOW + {"VERSION_TOO_LOW", ERR_LIB_SSL, SSL_R_VERSION_TOO_LOW}, + #else + {"VERSION_TOO_LOW", ERR_LIB_SSL, 396}, + #endif #ifdef SSL_R_WRITE_BIO_NOT_SET {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_WRITE_BIO_NOT_SET}, #else {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, 260}, #endif + #ifdef SSL_R_WRONG_CERTIFICATE_TYPE + {"WRONG_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_CERTIFICATE_TYPE}, + #else + {"WRONG_CERTIFICATE_TYPE", ERR_LIB_SSL, 383}, + #endif #ifdef SSL_R_WRONG_CIPHER_RETURNED {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, #else {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, 261}, #endif + #ifdef SSL_R_WRONG_CURVE + {"WRONG_CURVE", ERR_LIB_SSL, SSL_R_WRONG_CURVE}, + #else + {"WRONG_CURVE", ERR_LIB_SSL, 378}, + #endif #ifdef SSL_R_WRONG_MESSAGE_TYPE {"WRONG_MESSAGE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_MESSAGE_TYPE}, #else @@ -1499,6 +1754,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, 265}, #endif + #ifdef SSL_R_WRONG_SIGNATURE_TYPE + {"WRONG_SIGNATURE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_TYPE}, + #else + {"WRONG_SIGNATURE_TYPE", ERR_LIB_SSL, 370}, + #endif #ifdef SSL_R_WRONG_SSL_VERSION {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, #else @@ -1519,6 +1779,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, 269}, #endif + #ifdef X509_R_AKID_MISMATCH + {"AKID_MISMATCH", ERR_LIB_X509, X509_R_AKID_MISMATCH}, + #else + {"AKID_MISMATCH", ERR_LIB_X509, 110}, + #endif #ifdef X509_R_BAD_X509_FILETYPE {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, #else @@ -1539,11 +1804,26 @@ static struct py_ssl_error_code error_codes[] = { #else {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, 101}, #endif + #ifdef X509_R_CRL_ALREADY_DELTA + {"CRL_ALREADY_DELTA", ERR_LIB_X509, X509_R_CRL_ALREADY_DELTA}, + #else + {"CRL_ALREADY_DELTA", ERR_LIB_X509, 127}, + #endif + #ifdef X509_R_CRL_VERIFY_FAILURE + {"CRL_VERIFY_FAILURE", ERR_LIB_X509, X509_R_CRL_VERIFY_FAILURE}, + #else + {"CRL_VERIFY_FAILURE", ERR_LIB_X509, 131}, + #endif #ifdef X509_R_ERR_ASN1_LIB {"ERR_ASN1_LIB", ERR_LIB_X509, X509_R_ERR_ASN1_LIB}, #else {"ERR_ASN1_LIB", ERR_LIB_X509, 102}, #endif + #ifdef X509_R_IDP_MISMATCH + {"IDP_MISMATCH", ERR_LIB_X509, X509_R_IDP_MISMATCH}, + #else + {"IDP_MISMATCH", ERR_LIB_X509, 128}, + #endif #ifdef X509_R_INVALID_DIRECTORY {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, #else @@ -1559,6 +1839,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_TRUST", ERR_LIB_X509, 123}, #endif + #ifdef X509_R_ISSUER_MISMATCH + {"ISSUER_MISMATCH", ERR_LIB_X509, X509_R_ISSUER_MISMATCH}, + #else + {"ISSUER_MISMATCH", ERR_LIB_X509, 129}, + #endif #ifdef X509_R_KEY_TYPE_MISMATCH {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, #else @@ -1584,11 +1869,21 @@ static struct py_ssl_error_code error_codes[] = { #else {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, 124}, #endif + #ifdef X509_R_NEWER_CRL_NOT_NEWER + {"NEWER_CRL_NOT_NEWER", ERR_LIB_X509, X509_R_NEWER_CRL_NOT_NEWER}, + #else + {"NEWER_CRL_NOT_NEWER", ERR_LIB_X509, 132}, + #endif #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, #else {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, 105}, #endif + #ifdef X509_R_NO_CRL_NUMBER + {"NO_CRL_NUMBER", ERR_LIB_X509, X509_R_NO_CRL_NUMBER}, + #else + {"NO_CRL_NUMBER", ERR_LIB_X509, 130}, + #endif #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, #else diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py index 10244d1..3fb4985 100755 --- a/Tools/ssl/make_ssl_data.py +++ b/Tools/ssl/make_ssl_data.py @@ -5,8 +5,7 @@ This script should be called *manually* when we want to upgrade SSLError `library` and `reason` mnemnonics to a more recent OpenSSL version. It takes two arguments: -- the path to the OpenSSL include files' directory - (e.g. openssl-1.0.1-beta3/include/openssl/) +- the path to the OpenSSL source tree (e.g. git checkout) - the path to the C file to be generated (probably Modules/_ssl_data.h) """ @@ -15,9 +14,10 @@ import datetime import os import re import sys +import _ssl -def parse_error_codes(h_file, prefix): +def parse_error_codes(h_file, prefix, libcode): pat = re.compile(r"#define\W+(%s([\w]+))\W+(\d+)\b" % re.escape(prefix)) codes = [] with open(h_file, "r", encoding="latin1") as f: @@ -26,7 +26,8 @@ def parse_error_codes(h_file, prefix): if match: code, name, num = match.groups() num = int(num) - codes.append((code, name, num)) + # e.g. ("SSL_R_BAD_DATA", ("ERR_LIB_SSL", "BAD_DATA", 390)) + codes.append((code, (libcode, name, num))) return codes if __name__ == "__main__": @@ -34,12 +35,32 @@ if __name__ == "__main__": outfile = sys.argv[2] use_stdout = outfile == '-' f = sys.stdout if use_stdout else open(outfile, "w") - error_libraries = ( - # (library code, mnemonic, error prefix, header file) - ('ERR_LIB_PEM', 'PEM', 'PEM_R_', 'pem.h'), - ('ERR_LIB_SSL', 'SSL', 'SSL_R_', 'ssl.h'), - ('ERR_LIB_X509', 'X509', 'X509_R_', 'x509.h'), - ) + error_libraries = { + # mnemonic -> (library code, error prefix, header file) + 'PEM': ('ERR_LIB_PEM', 'PEM_R_', 'crypto/pem/pem.h'), + 'SSL': ('ERR_LIB_SSL', 'SSL_R_', 'ssl/ssl.h'), + 'X509': ('ERR_LIB_X509', 'X509_R_', 'crypto/x509/x509.h'), + } + + # Read codes from libraries + new_codes = [] + for libcode, prefix, h_file in sorted(error_libraries.values()): + new_codes += parse_error_codes(os.path.join(openssl_inc, h_file), + prefix, libcode) + new_code_nums = set((libcode, num) + for (code, (libcode, name, num)) in new_codes) + + # Merge with existing codes (in case some old codes disappeared). + codes = {} + for errname, (libnum, errnum) in _ssl.err_names_to_codes.items(): + lib = error_libraries[_ssl.lib_codes_to_names[libnum]] + libcode = lib[0] # e.g. ERR_LIB_PEM + errcode = lib[1] + errname # e.g. SSL_R_BAD_SSL_SESSION_ID_LENGTH + # Only keep it if the numeric codes weren't reused + if (libcode, errnum) not in new_code_nums: + codes[errcode] = libcode, errname, errnum + codes.update(dict(new_codes)) + def w(l): f.write(l + "\n") w("/* File generated by Tools/ssl/make_ssl_data.py */") @@ -47,21 +68,19 @@ if __name__ == "__main__": w("") w("static struct py_ssl_library_code library_codes[] = {") - for libcode, mnemo, _, _ in error_libraries: + for mnemo, (libcode, _, _) in sorted(error_libraries.items()): w(' {"%s", %s},' % (mnemo, libcode)) w(' { NULL }') w('};') w("") w("static struct py_ssl_error_code error_codes[] = {") - for libcode, _, prefix, h_file in error_libraries: - codes = parse_error_codes(os.path.join(openssl_inc, h_file), prefix) - for code, name, num in sorted(codes): - w(' #ifdef %s' % (code)) - w(' {"%s", %s, %s},' % (name, libcode, code)) - w(' #else') - w(' {"%s", %s, %d},' % (name, libcode, num)) - w(' #endif') + for errcode, (libcode, name, num) in sorted(codes.items()): + w(' #ifdef %s' % (errcode)) + w(' {"%s", %s, %s},' % (name, libcode, errcode)) + w(' #else') + w(' {"%s", %s, %d},' % (name, libcode, num)) + w(' #endif') w(' { NULL }') w('};') if not use_stdout: -- cgit v0.12 From 1b6e5381c326215fd0529832ec87c7b7056b8677 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 20 Jan 2015 06:55:51 +0200 Subject: Issue #22317: Document the action parameter in ArgumentParser.add_subparsers() docs. Patch by Mike Short. --- Doc/library/argparse.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index cda563d..fd75cfe 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1499,12 +1499,15 @@ Sub-commands * parser_class - class which will be used to create sub-parser instances, by default the class of the current parser (e.g. ArgumentParser) - * dest - name of the attribute under which sub-command name will be + * action_ - the basic type of action to be taken when this argument is + encountered at the command line + + * dest_ - name of the attribute under which sub-command name will be stored; by default None and no value is stored - * help - help for sub-parser group in help output, by default None + * help_ - help for sub-parser group in help output, by default None - * metavar - string presenting available sub-commands in help; by default it + * metavar_ - string presenting available sub-commands in help; by default it is None and presents sub-commands in form {cmd1, cmd2, ..} Some example usage:: -- cgit v0.12 From 6e3c3c3f19761e35b6320d5ec883f7089e01e2b6 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 21 Jan 2015 00:47:54 -0500 Subject: detect 64-bit systems using maxsize not maxint --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7868b7b..6a6ad23 100644 --- a/setup.py +++ b/setup.py @@ -696,7 +696,7 @@ class PyBuildExt(build_ext): exts.append( Extension('audioop', ['audioop.c']) ) # Disabled on 64-bit platforms - if sys.maxint != 9223372036854775807L: + if sys.maxsize != 9223372036854775807L: # Operations on images exts.append( Extension('imageop', ['imageop.c']) ) else: -- cgit v0.12 From 5e3b2dfef43298ea139c58c1b89a018f1bfb98f2 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Fri, 23 Jan 2015 21:18:02 +0000 Subject: Issue #23305: clarified RotatingFileHandler documentation. --- Doc/library/logging.handlers.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index d0f9be8..6731abc 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -185,15 +185,16 @@ module, supports rotation of disk log files. You can use the *maxBytes* and *backupCount* values to allow the file to :dfn:`rollover` at a predetermined size. When the size is about to be exceeded, the file is closed and a new file is silently opened for output. Rollover occurs - whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is - zero, rollover never occurs. If *backupCount* is non-zero, the system will save - old log files by appending the extensions '.1', '.2' etc., to the filename. For - example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you - would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to - :file:`app.log.5`. The file being written to is always :file:`app.log`. When - this file is filled, it is closed and renamed to :file:`app.log.1`, and if files - :file:`app.log.1`, :file:`app.log.2`, etc. exist, then they are renamed to - :file:`app.log.2`, :file:`app.log.3` etc. respectively. + whenever the current log file is nearly *maxBytes* in length; if either of + *maxBytes* or *backupCount* is zero, rollover never occurs. If *backupCount* + is non-zero, the system will save old log files by appending the extensions + '.1', '.2' etc., to the filename. For example, with a *backupCount* of 5 and + a base file name of :file:`app.log`, you would get :file:`app.log`, + :file:`app.log.1`, :file:`app.log.2`, up to :file:`app.log.5`. The file being + written to is always :file:`app.log`. When this file is filled, it is closed + and renamed to :file:`app.log.1`, and if files :file:`app.log.1`, + :file:`app.log.2`, etc. exist, then they are renamed to :file:`app.log.2`, + :file:`app.log.3` etc. respectively. .. versionchanged:: 2.6 *delay* was added. -- cgit v0.12 From b10bfbe036cec8b8a40e49c63c3206d52b106b5e Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 23 Jan 2015 16:35:37 -0500 Subject: pep 466 backport of alpn (#20188) --- Doc/library/ssl.rst | 34 ++++++++++++- Lib/ssl.py | 20 +++++++- Lib/test/test_ssl.py | 64 +++++++++++++++++++++++-- Misc/NEWS | 3 ++ Modules/_ssl.c | 132 ++++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 224 insertions(+), 29 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 62395f8..2a0817e 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -638,6 +638,13 @@ Constants .. versionadded:: 2.7.9 +.. data:: HAS_ALPN + + Whether the OpenSSL library has built-in support for the *Application-Layer + Protocol Negotiation* TLS extension as described in :rfc:`7301`. + + .. versionadded:: 3.5 + .. data:: HAS_ECDH Whether the OpenSSL library has built-in support for Elliptic Curve-based @@ -864,9 +871,18 @@ SSL sockets also have the following additional methods and attributes: .. versionadded:: 2.7.9 +.. method:: SSLSocket.selected_alpn_protocol() + + Return the protocol that was selected during the TLS handshake. If + :meth:`SSLContext.set_alpn_protocols` was not called, if the other party does + not support ALPN, or if the handshake has not happened yet, ``None`` is + returned. + + .. versionadded:: 3.5 + .. method:: SSLSocket.selected_npn_protocol() - Returns the higher-level protocol that was selected during the TLS/SSL + Return the higher-level protocol that was selected during the TLS/SSL handshake. If :meth:`SSLContext.set_npn_protocols` was not called, or if the other party does not support NPN, or if the handshake has not yet happened, this will return ``None``. @@ -1034,6 +1050,20 @@ to speed up repeated connections from the same clients. when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will give the currently selected cipher. +.. method:: SSLContext.set_alpn_protocols(protocols) + + Specify which protocols the socket should advertise during the SSL/TLS + handshake. It should be a list of ASCII strings, like ``['http/1.1', + 'spdy/2']``, ordered by preference. The selection of a protocol will happen + during the handshake, and will play out according to :rfc:`7301`. After a + successful handshake, the :meth:`SSLSocket.selected_alpn_protocol` method will + return the agreed-upon protocol. + + This method will raise :exc:`NotImplementedError` if :data:`HAS_ALPN` is + False. + + .. versionadded:: 3.5 + .. method:: SSLContext.set_npn_protocols(protocols) Specify which protocols the socket should advertise during the SSL/TLS @@ -1072,7 +1102,7 @@ to speed up repeated connections from the same clients. Due to the early negotiation phase of the TLS connection, only limited methods and attributes are usable like - :meth:`SSLSocket.selected_npn_protocol` and :attr:`SSLSocket.context`. + :meth:`SSLSocket.selected_alpn_protocol` and :attr:`SSLSocket.context`. :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.cipher` and :meth:`SSLSocket.compress` methods require that the TLS connection has progressed beyond the TLS Client Hello and therefore diff --git a/Lib/ssl.py b/Lib/ssl.py index 0f8ee1c..7b8f21a 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -123,7 +123,7 @@ _import_symbols('ALERT_DESCRIPTION_') _import_symbols('SSL_ERROR_') _import_symbols('PROTOCOL_') -from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN +from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN from _ssl import _OPENSSL_API_VERSION @@ -365,6 +365,17 @@ class SSLContext(_SSLContext): self._set_npn_protocols(protos) + def set_alpn_protocols(self, alpn_protocols): + protos = bytearray() + for protocol in alpn_protocols: + b = protocol.encode('ascii') + if len(b) == 0 or len(b) > 255: + raise SSLError('ALPN protocols must be 1 to 255 in length') + protos.append(len(b)) + protos.extend(b) + + self._set_alpn_protocols(protos) + def _load_windows_store_certs(self, storename, purpose): certs = bytearray() for cert, encoding, trust in enum_certificates(storename): @@ -647,6 +658,13 @@ class SSLSocket(socket): else: return self._sslobj.selected_npn_protocol() + def selected_alpn_protocol(self): + self._checkClosed() + if not self._sslobj or not _ssl.HAS_ALPN: + return None + else: + return self._sslobj.selected_alpn_protocol() + def cipher(self): self._checkClosed() if not self._sslobj: diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 4a6901c..711f494 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1569,7 +1569,8 @@ else: try: self.sslconn = self.server.context.wrap_socket( self.sock, server_side=True) - self.server.selected_protocols.append(self.sslconn.selected_npn_protocol()) + self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol()) + self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol()) except socket.error as e: # We treat ConnectionResetError as though it were an # SSLError - OpenSSL on Ubuntu abruptly closes the @@ -1678,7 +1679,8 @@ else: def __init__(self, certificate=None, ssl_version=None, certreqs=None, cacerts=None, chatty=True, connectionchatty=False, starttls_server=False, - npn_protocols=None, ciphers=None, context=None): + npn_protocols=None, alpn_protocols=None, + ciphers=None, context=None): if context: self.context = context else: @@ -1693,6 +1695,8 @@ else: self.context.load_cert_chain(certificate) if npn_protocols: self.context.set_npn_protocols(npn_protocols) + if alpn_protocols: + self.context.set_alpn_protocols(alpn_protocols) if ciphers: self.context.set_ciphers(ciphers) self.chatty = chatty @@ -1702,7 +1706,8 @@ else: self.port = support.bind_port(self.sock) self.flag = None self.active = False - self.selected_protocols = [] + self.selected_npn_protocols = [] + self.selected_alpn_protocols = [] self.conn_errors = [] threading.Thread.__init__(self) self.daemon = True @@ -1927,11 +1932,13 @@ else: 'compression': s.compression(), 'cipher': s.cipher(), 'peercert': s.getpeercert(), + 'client_alpn_protocol': s.selected_alpn_protocol(), 'client_npn_protocol': s.selected_npn_protocol(), 'version': s.version(), }) s.close() - stats['server_npn_protocols'] = server.selected_protocols + stats['server_alpn_protocols'] = server.selected_alpn_protocols + stats['server_npn_protocols'] = server.selected_npn_protocols return stats def try_protocol_combo(server_protocol, client_protocol, expect_success, @@ -2787,6 +2794,55 @@ else: if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: self.fail("Non-DH cipher: " + cipher[0]) + def test_selected_alpn_protocol(self): + # selected_alpn_protocol() is None unless ALPN is used. + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.load_cert_chain(CERTFILE) + stats = server_params_test(context, context, + chatty=True, connectionchatty=True) + self.assertIs(stats['client_alpn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support required") + def test_selected_alpn_protocol_if_server_uses_alpn(self): + # selected_alpn_protocol() is None unless ALPN is used by the client. + client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + client_context.load_verify_locations(CERTFILE) + server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + server_context.load_cert_chain(CERTFILE) + server_context.set_alpn_protocols(['foo', 'bar']) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True) + self.assertIs(stats['client_alpn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support needed for this test") + def test_alpn_protocols(self): + server_protocols = ['foo', 'bar', 'milkshake'] + protocol_tests = [ + (['foo', 'bar'], 'foo'), + (['bar', 'foo'], 'bar'), + (['milkshake'], 'milkshake'), + (['http/3.0', 'http/4.0'], 'foo') + ] + for client_protocols, expected in protocol_tests: + server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + server_context.load_cert_chain(CERTFILE) + server_context.set_alpn_protocols(server_protocols) + client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + client_context.load_cert_chain(CERTFILE) + client_context.set_alpn_protocols(client_protocols) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True) + + msg = "failed trying %s (s) and %s (c).\n" \ + "was expecting %s, but got %%s from the %%s" \ + % (str(server_protocols), str(client_protocols), + str(expected)) + client_result = stats['client_alpn_protocol'] + self.assertEqual(client_result, expected, msg % (client_result, "client")) + server_result = stats['server_alpn_protocols'][-1] \ + if len(stats['server_alpn_protocols']) else 'nothing' + self.assertEqual(server_result, expected, msg % (server_result, "server")) + def test_selected_npn_protocol(self): # selected_npn_protocol() is None unless NPN is used context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) diff --git a/Misc/NEWS b/Misc/NEWS index faf704a..f21dbe8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,9 @@ Core and Builtins Library ------- +- Issue #20188: Support Application-Layer Protocol Negotiation (ALPN) in the ssl + module. + - Issue #23248: Update ssl error codes from latest OpenSSL git master. - Issue #23098: 64-bit dev_t is now supported in the os module. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5758b86..db8a20b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -105,6 +105,11 @@ struct py_ssl_library_code { # define HAVE_SNI 0 #endif +/* ALPN added in OpenSSL 1.0.2 */ +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +# define HAVE_ALPN +#endif + enum py_ssl_error { /* these mirror ssl.h */ PY_SSL_ERROR_NONE, @@ -205,9 +210,13 @@ typedef struct { PyObject_HEAD SSL_CTX *ctx; #ifdef OPENSSL_NPN_NEGOTIATED - char *npn_protocols; + unsigned char *npn_protocols; int npn_protocols_len; #endif +#ifdef HAVE_ALPN + unsigned char *alpn_protocols; + int alpn_protocols_len; +#endif #ifndef OPENSSL_NO_TLSEXT PyObject *set_hostname; #endif @@ -1408,7 +1417,20 @@ static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { if (out == NULL) Py_RETURN_NONE; - return PyUnicode_FromStringAndSize((char *) out, outlen); + return PyString_FromStringAndSize((char *)out, outlen); +} +#endif + +#ifdef HAVE_ALPN +static PyObject *PySSL_selected_alpn_protocol(PySSLSocket *self) { + const unsigned char *out; + unsigned int outlen; + + SSL_get0_alpn_selected(self->ssl, &out, &outlen); + + if (out == NULL) + Py_RETURN_NONE; + return PyString_FromStringAndSize((char *)out, outlen); } #endif @@ -1925,6 +1947,9 @@ static PyMethodDef PySSLMethods[] = { #ifdef OPENSSL_NPN_NEGOTIATED {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, #endif +#ifdef HAVE_ALPN + {"selected_alpn_protocol", (PyCFunction)PySSL_selected_alpn_protocol, METH_NOARGS}, +#endif {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, PySSL_SSLshutdown_doc}, @@ -2032,6 +2057,9 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) #ifdef OPENSSL_NPN_NEGOTIATED self->npn_protocols = NULL; #endif +#ifdef HAVE_ALPN + self->alpn_protocols = NULL; +#endif #ifndef OPENSSL_NO_TLSEXT self->set_hostname = NULL; #endif @@ -2091,7 +2119,10 @@ context_dealloc(PySSLContext *self) context_clear(self); SSL_CTX_free(self->ctx); #ifdef OPENSSL_NPN_NEGOTIATED - PyMem_Free(self->npn_protocols); + PyMem_FREE(self->npn_protocols); +#endif +#ifdef HAVE_ALPN + PyMem_FREE(self->alpn_protocols); #endif Py_TYPE(self)->tp_free(self); } @@ -2117,6 +2148,23 @@ set_ciphers(PySSLContext *self, PyObject *args) Py_RETURN_NONE; } +static int +do_protocol_selection(unsigned char **out, unsigned char *outlen, + const unsigned char *remote_protocols, unsigned int remote_protocols_len, + unsigned char *our_protocols, unsigned int our_protocols_len) +{ + if (our_protocols == NULL) { + our_protocols = (unsigned char*)""; + our_protocols_len = 0; + } + + SSL_select_next_proto(out, outlen, + remote_protocols, remote_protocols_len, + our_protocols, our_protocols_len); + + return SSL_TLSEXT_ERR_OK; +} + #ifdef OPENSSL_NPN_NEGOTIATED /* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ static int @@ -2127,10 +2175,10 @@ _advertiseNPN_cb(SSL *s, PySSLContext *ssl_ctx = (PySSLContext *) args; if (ssl_ctx->npn_protocols == NULL) { - *data = (unsigned char *) ""; + *data = (unsigned char *)""; *len = 0; } else { - *data = (unsigned char *) ssl_ctx->npn_protocols; + *data = ssl_ctx->npn_protocols; *len = ssl_ctx->npn_protocols_len; } @@ -2143,23 +2191,9 @@ _selectNPN_cb(SSL *s, const unsigned char *server, unsigned int server_len, void *args) { - PySSLContext *ssl_ctx = (PySSLContext *) args; - - unsigned char *client = (unsigned char *) ssl_ctx->npn_protocols; - int client_len; - - if (client == NULL) { - client = (unsigned char *) ""; - client_len = 0; - } else { - client_len = ssl_ctx->npn_protocols_len; - } - - SSL_select_next_proto(out, outlen, - server, server_len, - client, client_len); - - return SSL_TLSEXT_ERR_OK; + PySSLContext *ctx = (PySSLContext *)args; + return do_protocol_selection(out, outlen, server, server_len, + ctx->npn_protocols, ctx->npn_protocols_len); } #endif @@ -2202,6 +2236,50 @@ _set_npn_protocols(PySSLContext *self, PyObject *args) #endif } +#ifdef HAVE_ALPN +static int +_selectALPN_cb(SSL *s, + const unsigned char **out, unsigned char *outlen, + const unsigned char *client_protocols, unsigned int client_protocols_len, + void *args) +{ + PySSLContext *ctx = (PySSLContext *)args; + return do_protocol_selection((unsigned char **)out, outlen, + client_protocols, client_protocols_len, + ctx->alpn_protocols, ctx->alpn_protocols_len); +} +#endif + +static PyObject * +_set_alpn_protocols(PySSLContext *self, PyObject *args) +{ +#ifdef HAVE_ALPN + Py_buffer protos; + + if (!PyArg_ParseTuple(args, "s*:set_npn_protocols", &protos)) + return NULL; + + PyMem_FREE(self->alpn_protocols); + self->alpn_protocols = PyMem_Malloc(protos.len); + if (!self->alpn_protocols) + return PyErr_NoMemory(); + memcpy(self->alpn_protocols, protos.buf, protos.len); + self->alpn_protocols_len = protos.len; + PyBuffer_Release(&protos); + + if (SSL_CTX_set_alpn_protos(self->ctx, self->alpn_protocols, self->alpn_protocols_len)) + return PyErr_NoMemory(); + SSL_CTX_set_alpn_select_cb(self->ctx, _selectALPN_cb, self); + + PyBuffer_Release(&protos); + Py_RETURN_NONE; +#else + PyErr_SetString(PyExc_NotImplementedError, + "The ALPN extension requires OpenSSL 1.0.2 or later."); + return NULL; +#endif +} + static PyObject * get_verify_mode(PySSLContext *self, void *c) { @@ -3188,6 +3266,8 @@ static struct PyMethodDef context_methods[] = { METH_VARARGS | METH_KEYWORDS, NULL}, {"set_ciphers", (PyCFunction) set_ciphers, METH_VARARGS, NULL}, + {"_set_alpn_protocols", (PyCFunction) _set_alpn_protocols, + METH_VARARGS, NULL}, {"_set_npn_protocols", (PyCFunction) _set_npn_protocols, METH_VARARGS, NULL}, {"load_cert_chain", (PyCFunction) load_cert_chain, @@ -4100,6 +4180,14 @@ init_ssl(void) Py_INCREF(r); PyModule_AddObject(m, "HAS_NPN", r); +#ifdef HAVE_ALPN + r = Py_True; +#else + r = Py_False; +#endif + Py_INCREF(r); + PyModule_AddObject(m, "HAS_ALPN", r); + /* Mappings for error codes */ err_codes_to_names = PyDict_New(); err_names_to_codes = PyDict_New(); -- cgit v0.12 From 65aa261eba8a4d9f335adfe826806e12fffa6429 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 23 Jan 2015 16:47:52 -0500 Subject: fix versionchanged --- Doc/library/ssl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 2a0817e..d9d68d1 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -643,7 +643,7 @@ Constants Whether the OpenSSL library has built-in support for the *Application-Layer Protocol Negotiation* TLS extension as described in :rfc:`7301`. - .. versionadded:: 3.5 + .. versionadded:: 2.7.10 .. data:: HAS_ECDH @@ -878,7 +878,7 @@ SSL sockets also have the following additional methods and attributes: not support ALPN, or if the handshake has not happened yet, ``None`` is returned. - .. versionadded:: 3.5 + .. versionadded:: 2.7.10 .. method:: SSLSocket.selected_npn_protocol() @@ -1062,7 +1062,7 @@ to speed up repeated connections from the same clients. This method will raise :exc:`NotImplementedError` if :data:`HAS_ALPN` is False. - .. versionadded:: 3.5 + .. versionadded:: 2.7.10 .. method:: SSLContext.set_npn_protocols(protocols) -- cgit v0.12 From aa7075845cdb8dd44a9991b6fdece6f68fd9ecd1 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 23 Jan 2015 17:30:26 -0500 Subject: prefer server alpn ordering over the client's --- Doc/library/ssl.rst | 3 ++- Lib/test/test_ssl.py | 4 ++-- Modules/_ssl.c | 33 ++++++++++++++++++++------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index d9d68d1..b261eee 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -875,7 +875,8 @@ SSL sockets also have the following additional methods and attributes: Return the protocol that was selected during the TLS handshake. If :meth:`SSLContext.set_alpn_protocols` was not called, if the other party does - not support ALPN, or if the handshake has not happened yet, ``None`` is + not support ALPN, if this socket does not support any of the client's + proposed protocols, or if the handshake has not happened yet, ``None`` is returned. .. versionadded:: 2.7.10 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 711f494..f3da0b1 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2819,9 +2819,9 @@ else: server_protocols = ['foo', 'bar', 'milkshake'] protocol_tests = [ (['foo', 'bar'], 'foo'), - (['bar', 'foo'], 'bar'), + (['bar', 'foo'], 'foo'), (['milkshake'], 'milkshake'), - (['http/3.0', 'http/4.0'], 'foo') + (['http/3.0', 'http/4.0'], None) ] for client_protocols, expected in protocol_tests: server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index db8a20b..1528742 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2149,18 +2149,25 @@ set_ciphers(PySSLContext *self, PyObject *args) } static int -do_protocol_selection(unsigned char **out, unsigned char *outlen, - const unsigned char *remote_protocols, unsigned int remote_protocols_len, - unsigned char *our_protocols, unsigned int our_protocols_len) +do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen, + const unsigned char *server_protocols, unsigned int server_protocols_len, + const unsigned char *client_protocols, unsigned int client_protocols_len) { - if (our_protocols == NULL) { - our_protocols = (unsigned char*)""; - our_protocols_len = 0; + int ret; + if (client_protocols == NULL) { + client_protocols = (unsigned char *)""; + client_protocols_len = 0; + } + if (server_protocols == NULL) { + server_protocols = (unsigned char *)""; + server_protocols_len = 0; } - SSL_select_next_proto(out, outlen, - remote_protocols, remote_protocols_len, - our_protocols, our_protocols_len); + ret = SSL_select_next_proto(out, outlen, + server_protocols, server_protocols_len, + client_protocols, client_protocols_len); + if (alpn && ret != OPENSSL_NPN_NEGOTIATED) + return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_OK; } @@ -2192,7 +2199,7 @@ _selectNPN_cb(SSL *s, void *args) { PySSLContext *ctx = (PySSLContext *)args; - return do_protocol_selection(out, outlen, server, server_len, + return do_protocol_selection(0, out, outlen, server, server_len, ctx->npn_protocols, ctx->npn_protocols_len); } #endif @@ -2244,9 +2251,9 @@ _selectALPN_cb(SSL *s, void *args) { PySSLContext *ctx = (PySSLContext *)args; - return do_protocol_selection((unsigned char **)out, outlen, - client_protocols, client_protocols_len, - ctx->alpn_protocols, ctx->alpn_protocols_len); + return do_protocol_selection(1, (unsigned char **)out, outlen, + ctx->alpn_protocols, ctx->alpn_protocols_len, + client_protocols, client_protocols_len); } #endif -- cgit v0.12 From 812b9756a0626b6915c3ff5563e51def9e968580 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Sat, 24 Jan 2015 12:58:10 -0800 Subject: Fix Issue23300 : httplib.HTTP classe's connect method should use _get_hostport instead of (non-existing) _set_hostport. (Fix the regression introduced in 568041fd8090 ) --- Lib/httplib.py | 4 ++-- Lib/test/test_httplib.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Lib/httplib.py b/Lib/httplib.py index c43fd29..194e130 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -723,7 +723,7 @@ class HTTPConnection: endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT request to the proxy server when the connection is established. - This method must be called before the HTML connection has been + This method must be called before the HTTP connection has been established. The headers argument should be a mapping of extra HTTP headers @@ -1129,7 +1129,7 @@ class HTTP: "Accept arguments to set the host/port, since the superclass doesn't." if host is not None: - self._conn._set_hostport(host, port) + (self._conn.host, self._conn.port) = self._conn._get_hostport(host, port) self._conn.connect() def getfile(self): diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 011609b..0892d5a 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -461,7 +461,11 @@ class OfflineTest(TestCase): self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found") -class SourceAddressTest(TestCase): +class TestServerMixin: + """A limited socket server mixin. + + This is used by test cases for testing http connection end points. + """ def setUp(self): self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.port = test_support.bind_port(self.serv) @@ -476,6 +480,7 @@ class SourceAddressTest(TestCase): self.serv.close() self.serv = None +class SourceAddressTest(TestServerMixin, TestCase): def testHTTPConnectionSourceAddress(self): self.conn = httplib.HTTPConnection(HOST, self.port, source_address=('', self.source_port)) @@ -492,6 +497,24 @@ class SourceAddressTest(TestCase): # for an ssl_wrapped connect() to actually return from. +class HTTPTest(TestServerMixin, TestCase): + def testHTTPConnection(self): + self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None) + self.conn.connect() + self.assertEqual(self.conn._conn.host, HOST) + self.assertEqual(self.conn._conn.port, self.port) + + def testHTTPWithConnectHostPort(self): + testhost = 'unreachable.test.domain' + testport = '80' + self.conn = httplib.HTTP(host=testhost, port=testport) + self.conn.connect(host=HOST, port=self.port) + self.assertNotEqual(self.conn._conn.host, testhost) + self.assertNotEqual(self.conn._conn.port, testport) + self.assertEqual(self.conn._conn.host, HOST) + self.assertEqual(self.conn._conn.port, self.port) + + class TimeoutTest(TestCase): PORT = None @@ -537,6 +560,7 @@ class TimeoutTest(TestCase): self.assertEqual(httpConn.sock.gettimeout(), 30) httpConn.close() + class HTTPSTest(TestCase): def setUp(self): @@ -713,7 +737,8 @@ class TunnelTests(TestCase): @test_support.reap_threads def test_main(verbose=None): test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, - HTTPSTest, SourceAddressTest, TunnelTests) + HTTPTest, HTTPSTest, SourceAddressTest, + TunnelTests) if __name__ == '__main__': test_main() -- cgit v0.12 From f8fe12a5a6d27fc0616e68e27755f0c963b8e98c Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sun, 25 Jan 2015 15:48:26 -0500 Subject: #23251: note that time.sleep affects the current thread only. This is parallel to the language used in the unix man page. --- Doc/library/time.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst index 04ddef9..12b05bd 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -222,7 +222,8 @@ The module defines the following functions and data items: .. function:: sleep(secs) - Suspend execution for the given number of seconds. The argument may be a + Suspend execution of the current thread for the given number of seconds. + The argument may be a floating point number to indicate a more precise sleep time. The actual suspension time may be less than that requested because any caught signal will terminate the :func:`sleep` following execution of that signal's catching -- cgit v0.12 From 9a6d32e78cd8f73f957d6c8eac04fb3f834fc261 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sun, 25 Jan 2015 15:48:47 -0500 Subject: #23251: Reflow paragraph. --- Doc/library/time.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst index 12b05bd..be2dd15 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -223,12 +223,12 @@ The module defines the following functions and data items: .. function:: sleep(secs) Suspend execution of the current thread for the given number of seconds. - The argument may be a - floating point number to indicate a more precise sleep time. The actual - suspension time may be less than that requested because any caught signal will - terminate the :func:`sleep` following execution of that signal's catching - routine. Also, the suspension time may be longer than requested by an arbitrary - amount because of the scheduling of other activity in the system. + The argument may be a floating point number to indicate a more precise sleep + time. The actual suspension time may be less than that requested because any + caught signal will terminate the :func:`sleep` following execution of that + signal's catching routine. Also, the suspension time may be longer than + requested by an arbitrary amount because of the scheduling of other activity + in the system. .. function:: strftime(format[, t]) -- cgit v0.12 From bfd976fc171bd89080ecbbb2d64ed1bc315fa2a9 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sun, 25 Jan 2015 23:34:42 -0500 Subject: simply ignore headers with no name (#19996) Patch by Cory Benfield. --- Lib/httplib.py | 5 +++++ Lib/rfc822.py | 7 ++++++- Lib/test/test_httplib.py | 10 ++++++++++ Lib/test/test_rfc822.py | 6 ++++++ Misc/NEWS | 3 +++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Lib/httplib.py b/Lib/httplib.py index 194e130..8a6ad81 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -313,6 +313,11 @@ class HTTPMessage(mimetools.Message): hlist.append(line) self.addheader(headerseen, line[len(headerseen)+1:].strip()) continue + elif headerseen is not None: + # An empty header name. These aren't allowed in HTTP, but it's + # probably a benign mistake. Don't add the header, just keep + # going. + continue else: # It's not a header line; throw it back and stop here. if not self.dict: diff --git a/Lib/rfc822.py b/Lib/rfc822.py index b65d8da..c1d0865 100644 --- a/Lib/rfc822.py +++ b/Lib/rfc822.py @@ -179,6 +179,11 @@ class Message: lst.append(line) self.dict[headerseen] = line[len(headerseen)+1:].strip() continue + elif headerseen is not None: + # An empty header name. These aren't allowed in HTTP, but it's + # probably a benign mistake. Don't add the header, just keep + # going. + continue else: # It's not a header line; throw it back and stop here. if not self.dict: @@ -202,7 +207,7 @@ class Message: data in RFC 2822-like formats with special header formats. """ i = line.find(':') - if i > 0: + if i > -1: return line[:i].lower() return None diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 0892d5a..c071411 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -164,6 +164,16 @@ class HeaderTests(TestCase): conn.request('GET', '/foo') self.assertTrue(sock.data.startswith(expected)) + def test_malformed_headers_coped_with(self): + # Issue 19996 + body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n" + sock = FakeSocket(body) + resp = httplib.HTTPResponse(sock) + resp.begin() + + self.assertEqual(resp.getheader('First'), 'val') + self.assertEqual(resp.getheader('Second'), 'val') + class BasicTest(TestCase): def test_status_lines(self): diff --git a/Lib/test/test_rfc822.py b/Lib/test/test_rfc822.py index d8a0280..cdd8c9c 100644 --- a/Lib/test/test_rfc822.py +++ b/Lib/test/test_rfc822.py @@ -248,6 +248,12 @@ A test message. eq(rfc822.quote('foo\\wacky"name'), 'foo\\\\wacky\\"name') eq(rfc822.unquote('"foo\\\\wacky\\"name"'), 'foo\\wacky"name') + def test_invalid_headers(self): + eq = self.assertEqual + msg = self.create_message("First: val\n: otherval\nSecond: val2\n") + eq(msg.getheader('First'), 'val') + eq(msg.getheader('Second'), 'val2') + def test_main(): test_support.run_unittest(MessageTestCase) diff --git a/Misc/NEWS b/Misc/NEWS index f21dbe8..6582bab 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,9 @@ Core and Builtins Library ------- +- Issue #19996: Make :mod:`httplib` ignore headers with no name rather than + assuming the body has started. + - Issue #20188: Support Application-Layer Protocol Negotiation (ALPN) in the ssl module. -- cgit v0.12