Convert OpenSSL resources to objects#5860
Conversation
00f354b to
095b0bb
Compare
3b9fadf to
bdc6f88
Compare
18a02cc to
91f9233
Compare
91f9233 to
e6e5260
Compare
e6e5260 to
2d98cc3
Compare
|
@bukka probably also want to have a look at this. |
ext/openssl/openssl.c
Outdated
| x509_certificate_object_handlers.clone_obj = NULL; | ||
|
|
||
| zend_class_entry csr_ce; | ||
| INIT_CLASS_ENTRY(csr_ce, "X509CertificateSigningRequest", class_X509CertificateSigningRequest_methods); |
ext/openssl/openssl.c
Outdated
| x509_request_object_handlers.clone_obj = NULL; | ||
|
|
||
| zend_class_entry key_ce; | ||
| INIT_CLASS_ENTRY(key_ce, "OpenSSLKey", class_OpenSSLKey_methods); |
There was a problem hiding this comment.
Please use OpenSSLPKey or something showing that it's about pub priv key. Maybe something like OpenSSLAsymmetricKey...
There was a problem hiding this comment.
I'd be very much in favour of the latter, since it took me quite some googling and time to find out if the "p" means private or public in the pkey related names. Then I realized it's for both :)
There was a problem hiding this comment.
What's your stance about the OpenSSLX509CertificateSigningRequest class name? I'm not shy at all to give long names, but it's very-very close to my threshold (probably it's over it). :) Do we still need the X509 here and in the certificate's class name if the OpenSSL prefix is applied?
There was a problem hiding this comment.
My preferences are: OpenSSLCertificate, OpenSSLCertificateSigningRequest, and OpenSSLAsymmetricKey (or OpenSSLKey). In 99% of the cases, I don't like to write abbreviations with all capital letters (I forgot the name of this style), but unfortunately, Ssl maybe doesn't look that good. :(
There was a problem hiding this comment.
Yeah I like OpenSSLCertificate, OpenSSLCertificateSigningRequest, and OpenSSLAsymmetricKey
ext/openssl/openssl.c
Outdated
| RETURN_THROWS(); | ||
| } | ||
| ZEND_PARSE_PARAMETERS_START(2, 3) | ||
| Z_PARAM_STR_OR_OBJ_OF_CLASS(cert_str, cert_obj, x509_certificate_ce) |
There was a problem hiding this comment.
so this actually prevents stringified object to be passed which has been supported so this breaking the functionality somehow.
There was a problem hiding this comment.
I think this should be kept as zval
There was a problem hiding this comment.
This still allows stringified objects per PHP's usual type declaration semantics. (In weak typing mode only of course, but that's a language consistency requirement.)
There was a problem hiding this comment.
Ah yeah that's good then. I think we can drop that object OR string condition in that case.
ext/openssl/openssl.c
Outdated
| RETURN_THROWS(); | ||
| } | ||
| ZEND_PARSE_PARAMETERS_START(2, 3) | ||
| Z_PARAM_STR_OR_OBJ_OF_CLASS(cert_str, cert_obj, x509_certificate_ce) |
There was a problem hiding this comment.
again should be kept as zval probably...
There was a problem hiding this comment.
this has been answered above and it's ok.
|
Nice work! Added some comments. Didn't manage to get through all of it but lots of issues are kind of the same then. |
ext/openssl/openssl.c
Outdated
| x509_certificate_object_handlers.offset = XtOffsetOf(x509_certificate_object, std); | ||
| x509_certificate_object_handlers.free_obj = x509_certificate_free_obj; | ||
| x509_certificate_object_handlers.get_constructor = x509_certificate_get_constructor; | ||
| x509_certificate_object_handlers.clone_obj = NULL; |
There was a problem hiding this comment.
How is cloning going to be handled? I think we should be be using refs up in 1.1 and dup 1.0 possibly.
There was a problem hiding this comment.
Cloning is currently disabled. I'm not sure I'll have enough time to incorporate its support in this PR before feature freeze starts (next Tuesday), but I can make a follow-up PR afterwards.
There was a problem hiding this comment.
I don't think cloning should be part of the migration itself. It's a separate feature that allows doing something the current API doesn't (you can't clone a resource). The only case where we have added cloning support until now are curl handles, because the resource API already exposed an equivalent function (curl_copy_handle).
ext/openssl/openssl.c
Outdated
| zend_class_entry csr_ce; | ||
| INIT_CLASS_ENTRY(csr_ce, "X509CertificateSigningRequest", class_X509CertificateSigningRequest_methods); | ||
| x509_request_ce = zend_register_internal_class(&csr_ce); | ||
| x509_request_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES; |
There was a problem hiding this comment.
this reminds me that instantiation should be also prohibited for all classes (meaning something like private constructor)
There was a problem hiding this comment.
Yes, that's right! The constructors currently emit an exception with the Cannot directly construct... message, which is in line what we did for other resource migrations.
2d98cc3 to
c637781
Compare
|
@bukka Thanks for the quick review! I've just added a new commit where I tried to fix as much of the comments as I could :) There's one test failing currently, so I'll have a closer look at it in the morning. |
c637781 to
118a330
Compare
ext/openssl/openssl.c
Outdated
|
|
||
| static X509 *php_openssl_x509_from_zval(zval *val, bool *free_cert) | ||
| { | ||
| *free_cert = 1; |
There was a problem hiding this comment.
I'd move this assignment below the if.
ext/openssl/openssl.c
Outdated
| } | ||
|
|
||
| if (keyresource == NULL && s != NULL) { | ||
| if (free_pkey && s != NULL) { |
There was a problem hiding this comment.
This doesn't make sense, s and free_pkey have no relation. This branch should just be dropped. (Because free_pkey is always false in this code, it ends up not mattering.)
ext/openssl/openssl.c
Outdated
|
|
||
| /* OpenSSLAsymmetricKey class */ | ||
|
|
||
| typedef struct _openssl_key_object { |
|
|
||
| object_init_ex(return_value, php_openssl_pkey_ce); | ||
| key_object = Z_OPENSSL_PKEY_P(return_value); | ||
| key_object->pkey = pkey; |
There was a problem hiding this comment.
This may cause a use after free if it is an existing pkey and not a newly created one. Unfortunately there is no EVP_PKEY_dup, and EVP_PKEY_up_ref is OpenSSL 1.1. The previous code side-stepped the issue by reusing the existing pkey resource (as this only happens for the trivial case where you get the public key from ... a public key).
The structure is actually refcounted on older OpenSSL versions as well, but one has to use the lower-level CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY) API there.
There was a problem hiding this comment.
We can redefine EVP_PKEY_up_ref if it's below 1.1 as it's done for some other functions. Might need some handling for freeing the key. It probably needs some testing. Considering the FF I'd be fine to get this in with leaking 1.0.2 if the PR to fix it is created later in the beta...
It also reminds me that we should drop support for 1.0.1. I'm kind of inclined dropping support for 1.0.2 too but might be too inconvenient for some RHEL 7 users. Considering that it's still supported in there, we should probably keep 1.0.2 support.
There was a problem hiding this comment.
Sorry meant crashing 1.0.2 (use after free). But if there is time for fixing that on 1.0.2, then even better. :)
There was a problem hiding this comment.
I went with using EVP_PKEY_up_ref() and defining a compatibility shim for older versions. I've also built OpenSSL 1.0.1u and checked that everything works under asan.
There was a problem hiding this comment.
Ah yeah it's all good. I just double checked EVP_PKEY_free code in 1.0.2 and it's considering the ref:
void EVP_PKEY_free(EVP_PKEY *x)
{
int i;
if (x == NULL)
return;
i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
#ifdef REF_PRINT
REF_PRINT("EVP_PKEY", x);
#endif
if (i > 0)
return;
#ifdef REF_CHECK
if (i < 0) {
fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
abort();
}
#endif
EVP_PKEY_free_it(x);
if (x->attributes)
sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
OPENSSL_free(x);
}
There was a problem hiding this comment.
Thanks, Nikita for fixing this for me. I wouldn't have found out on my own that this causes the test failure. :)
ext/openssl/openssl.c
Outdated
| NETSCAPE_SPKI_free(spki); | ||
| } | ||
| if (keyresource == NULL && pkey != NULL) { | ||
| if (free_pkey && pkey != NULL) { |
There was a problem hiding this comment.
and this should be also dropped for the same reason as the below.
And define compat shim for EVP_PKEY_up_ref().
ext/openssl/openssl.c
Outdated
|
|
||
| #endif | ||
|
|
||
| #if PHP_OPENSSL_API_VERSION < 0x10100 |
There was a problem hiding this comment.
Is this the right version, isn't it?
| cert = php_openssl_x509_from_param(cert_obj, cert_str); | ||
| if (cert == NULL) { | ||
| php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1"); | ||
| php_error_docref(NULL, E_WARNING, "X.509 Certificate cannot be retrieved"); |
There was a problem hiding this comment.
Should I change these kind of error messages to argument #1 ($x509) must be a valid X.509 Certificate?
UPDATE: Probably I'll do it later if you also like this format, this PR is already huge
|
|
||
| object_init_ex(return_value, php_openssl_pkey_ce); | ||
| key_object = Z_OPENSSL_PKEY_P(return_value); | ||
| key_object->pkey = pkey; |
There was a problem hiding this comment.
Thanks, Nikita for fixing this for me. I wouldn't have found out on my own that this causes the test failure. :)
7a5715a to
36aed21
Compare
| object_init_ex(return_value, php_openssl_pkey_ce); | ||
| key_object = Z_OPENSSL_PKEY_P(return_value); | ||
| key_object->pkey = pkey; |
There was a problem hiding this comment.
It might be good to create a macro for this as it's constantly repeated. Doesn't need to be in the PR - just a note for future improvement.
| bool(true) | ||
| Load key from file - array syntax | ||
|
|
||
| Deprecated: Function openssl_pkey_free() is deprecated in %s on line %d |
There was a problem hiding this comment.
we should probably remove it from the test if it's deprecated - again doesn't need to be done now.
| for ($i = 0; $i < 100000; $i++) { | ||
| $a = openssl_get_publickey($b); | ||
| openssl_free_key($a); | ||
| @openssl_free_key($a); |
There was a problem hiding this comment.
Hmm we should probably look to this test if it's needed as well (future scope)
| object_init_ex(&zcert, php_openssl_certificate_ce); | ||
| cert_object = Z_OPENSSL_CERTIFICATE_P(&zcert); | ||
| cert_object->x509 = peer_cert; |
There was a problem hiding this comment.
again macro would be good for this (future scope)
|
@kocsismate Think it's good to go. There are just some suggestion but for them it's probably better to do a different PR. |
|
@kocsismate would be good if you can merge it soon so we can also get in #5111 before FF. |
|
@bukka, sure, I can merge it in the late evening. I'll also provide a few followup PRs. |
> - The openssl_x509_free() function is deprecated and no longer has an effect, > instead the OpenSSLCertificate instance is automatically destroyed if it is no > longer referenced. > - The openssl_pkey_free() function is deprecated and no longer has an effect, > instead the OpenSSLAsymmetricKey instance is automatically destroyed if it is no > longer referenced. Refs: * https://github.com/php/php-src/blob/71bfa5344ab207072f4cd25745d7023096338385/UPGRADING#L384-L399 * php/php-src#5860 * php/php-src@9f44eca#diff-7748eb3bfdd3bf962553f6f9f2723c45 Includes unit tests.
No description provided.