-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use OpenSSLPKey
or something showing that it's about pub priv key. Maybe something like OpenSSLAsymmetricKey
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be kept as zval
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again should be kept as zval probably...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok it can be done later.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this reminds me that instantiation should be also prohibited for all classes (meaning something like private constructor)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move this assignment below the if.
ext/openssl/openssl.c
Outdated
EVP_PKEY_free(pkey); | ||
} | ||
|
||
if (s && ZSTR_LEN(s) <= 0) { | ||
RETVAL_FALSE; | ||
} | ||
|
||
if (keyresource == NULL && s != NULL) { | ||
if (free_pkey && s != NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: _php_openssl_pkey_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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -1496,15 +1611,15 @@ PHP_FUNCTION(openssl_spki_new) | |||
if (spki != NULL) { | |||
NETSCAPE_SPKI_free(spki); | |||
} | |||
if (keyresource == NULL && pkey != NULL) { | |||
if (free_pkey && pkey != NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -277,6 +390,15 @@ static int X509_get_signature_nid(const X509 *x) | |||
|
|||
#endif | |||
|
|||
#if PHP_OPENSSL_API_VERSION < 0x10100 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the right version, isn't it?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Creating private key | ||
Export key to file | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably remove it from the test if it's deprecated - again doesn't need to be done now.
@@ -17,7 +17,7 @@ C9C4JmhTOjBVAK8SewIDAQAC | |||
$start = memory_get_usage(true); | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.