-
Notifications
You must be signed in to change notification settings - Fork 304
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
HPCC-27255 TLS cert/key as buffers #17719
Conversation
https://track.hpccsystems.com/browse/HPCC-27255 |
@afishbeck is this what you are sort of looking for ? |
@jakesmith this is a draft PR - let me know your thoughts. |
@mckellyln I haven't reviewed the details, but this functionality looks great. The one thing that would make this just sort of work magically for much of the kubernetes code is if you updated this constructor: CSecureSocketContext(const IPropertyTree* config, SecureSocketType sockettype) So that it detects if the following are file paths like they are now, or memory buffers. If the ptree could support either then it would become almost seemless.
Can verify the path to the cacert pem buffer later, but that's the idea. |
ok, I've added code for this, thanks. |
@mckellyln I made a minor suggestion above. Other than that, I haven't reviewed the fine points, but the design looks great. I will be able to make use of this to allow more certificates to come from vault rather than local secrets. |
ok, thanks, I will remove the '@' from the '@pem' |
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.
@mckellyln - looks good, a few minor points and questions, main one may be - is const char * the best choice for these certificate buffers that ultimately call through to the methods that take a void * + len ?
STACK_OF(X509_INFO) *infostk = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); | ||
if (!infostk) | ||
{ | ||
BIO_free(cbio); |
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.
minor: it would be safer to 'own' the BIO pointer, would avoid the manual free's and guarantee (e.g. if exception) that it would be freed, e.g. with:
cryptohelper::OwnedEVPBio cbio = BIO_new_mem_buf((void *)certbuf, -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.
worth considering for similar cleanup code, e.g. when SSL_CTX_free called
|
||
return false; | ||
} | ||
|
||
class CSecureSocketContext : implements ISecureSocketContext, public CInterface |
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.
not new: slightly more efficient (avoids VMT) to do : public CInterfaceOf
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, changed
char errbuf[512]; | ||
ERR_error_string_n(ERR_get_error(), errbuf, 512); | ||
SSL_CTX_free(m_ctx); | ||
throw MakeStringException(-1, "error loading certificate chain %s", errbuf); |
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.
trivial: MakeStringException is deprecated in favour of makeStringException or makeStringExceptionV
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.
@mckellyln a few comments. I didn't look in detail at the functions.
|
||
if (!isEmptyString(clientCertBuf)) | ||
{ | ||
info->setProp("certificatebuf", clientCertBuf); |
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.
@afishbeck there is a mixture of attributes (enable, accept) and values (trusted_peers, pem, certificatebuf etc.) is there a reason for each?
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.
@ghalliday There is, this is basically config for a SecureSocket to be used for either client or server. It's been around quite a while, and used multiple places. I create some from secrets which is where this PR comes from. We could clean it up at some point (along with much of the SecureSocket interface), but it would be a separate effort.
if (client_cert_.length() || ca_certs_.length() || accept_self_signed_) | ||
|
||
if (client_cert_buf_.length() || ca_certs_buf_.length()) | ||
soapclient.setSecureSocketConfig(createSecClientConfigBuf(client_cert_buf_, client_priv_key_buf_, ca_certs_buf_, accept_self_signed_)); |
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.
may be simpler as a single function that also takes the buffer parameters - it would remove some duplicate code and would also work with a mixuture of buffers and files (although I can't see that being used)
RSA *rsa = PEM_read_bio_RSAPrivateKey(cbio, NULL, 0, NULL); | ||
if (rsa == NULL) | ||
{ | ||
BIO_free(cbio); |
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.
Worth using a wrapper class for a BIO * which calls BIO_free on exit. It would clean up the code in this and other functions.
... I see Jake has suggested the same below. I think the following works (it compiles!), and might be a good pattern to adopt elsewhere:
struct BIO_deleter
{
void operator() ( BIO * bio )
{
BIO_free( bio );
}
};
using unique_bioptr = std::unique_ptr<BIO, BIO_deleter>;
...
unique_bioptr cbio(BIO_new_mem_buf((void *)privkeybuf, -1));
@jakesmith thoughts?
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.
std::unique_ptr vs cryptohelper::OwnedEVPBio would be okay too, and more standard.
Only -ve is that std::unique_ptr doesn't implicitly cast to the underlying pointer the way we are used to with our Owned* varieties [i.e. u need to call uptr.get() ]
Either would make the code cleaner/safer.
It would be nice if we consistently use the same pattern though.
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, added for BIO.
Perhaps could also do same for stack of x509 ...
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, I think in almost all cases, it would be cleaner/safer and make the code more robust in general (the pke/cryptocommon code does so for all SSL objects).
9ab52fe
to
6ba3969
Compare
Have made many updates in commit 4 to address your comments. |
if (!cbio) | ||
return false; | ||
|
||
STACK_OF(X509_INFO) *infostk = PEM_X509_INFO_read_bio(cbio.get(), NULL, NULL, 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.
perhaps a unique_ptr could be used for infostk as well ?
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, I think it would help the code be more robust in general if we contained these objects, such as they were auto deleted when out of scope.
build / checks failed because of something not related to code changes -
|
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.
@mckellyln - please see comments
setRpcSSLOptions(rpc, true, clientCertFilename, clientPrivateKeyFilename, caCertFilename, false); | ||
Owned<IPropertyTree> secretPTree = getSecret("storage", secretName); | ||
if (!secretPTree) | ||
throw MakeStringException(-1, "secret %s.%s not found", "storage", secretName); |
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.
trivial: this should really be makeStringExceptionV, also in some other places new and old.
virtual void setClientCertificate(const char *certPath, const char *privateKeyPath) override | ||
{ | ||
client_cert_.set(certPath); | ||
client_priv_key_.set(privateKeyPath); | ||
} | ||
|
||
void setCACertificatesBuf(const char *caCertBuf) override {ca_certs_buf_.set(caCertBuf);} |
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.
personal: not keen on formatting like this, clearer if spaced and on newlines IMO.
|
||
void setCACertificatesBuf(const char *caCertBuf) override {ca_certs_buf_.set(caCertBuf);} | ||
|
||
virtual void setClientCertificateBuf(const char *certBuf, const char *privKeyBuf) |
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.
minor: missing 'override'
|
||
SSL_CTX_set_mode(m_ctx, SSL_CTX_get_mode(m_ctx) | SSL_MODE_AUTO_RETRY); | ||
} | ||
|
||
CSecureSocketContext(const char* certfile, const char* privkeyfile, const char* passphrase, SecureSocketType sockettype) | ||
CSecureSocketContext(StringBuffer& certBuf, StringBuffer& privkeyBuf, const char* passphrase, SecureSocketType sockettype) |
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.
currently, this new constructor isn't used, but also it's confusing that there's 1 ctor taking 2 const char *'s and another taking 2 StringBuffer's.
I think as with the property config ctor, it would be better to consolidate into 1, which differentiated whether a file or content, via isPEMBuffer().
There's quite a bit of common code here too (was to some extent before as well), it would be cleaner/clearer to read if there were member helper functions, e.g. setCertificateFromBuf, setCertificateFromFile, and same for private key.
The calling code in ctor's could then reuse, and with the above change, both can call a common setCertificate and setPrivateKey private member methods, i.e.
void setCertificate(const char *certificate)
{
if (isPEMBuffer(certificate))
setCertificateFromBuf(certificate);
else
setCertificateFromFile(certificate);
}
void setPrivateKey(const char *privateKey)
{
if (isPEMBuffer(privateKey))
setPrivateKeyFromBuf(privateKey);
else
setPrivateKeyFromFile(privateKey);
}
const char* privkeyfile = config->queryProp("privatekey"); | ||
if(privkeyfile && *privkeyfile) | ||
bool hasPrivKey = false; | ||
const char* privkeybuf = config->queryProp("privatekeybuf"); |
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.
trivial: quite a lot of pre-existing mixed conventions in use already, but we should try to use camelCase for new/changed code.
if(!SSL_CTX_check_private_key(m_ctx)) | ||
{ | ||
SSL_CTX_free(m_ctx); |
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.
agree, management of these types of objects would be cleaner/safer if owned (e.g. with unique_ptr).
and if this code is moved into the helper methods that handle private key setting, then it will be more relevant, as it will be owned by the class - the free would not need to happen at this point.
if (!cbio) | ||
return false; | ||
|
||
RSA *rsa = PEM_read_bio_RSAPrivateKey(cbio.get(), NULL, 0, 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.
I think this is being leaked (similar code in pke.cpp, ensures it is owned)
if (!cbio) | ||
return false; | ||
|
||
STACK_OF(X509_INFO) *infostk = PEM_X509_INFO_read_bio(cbio.get(), NULL, NULL, 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.
yes, I think it would help the code be more robust in general if we contained these objects, such as they were auto deleted when out of scope.
return false; | ||
} | ||
|
||
class CSecureSocketContext : public CInterfaceOf<ISecureSocketContext> | ||
{ | ||
private: | ||
SSL_CTX* m_ctx = nullptr; |
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 would help clearup other code if this was owned.
f89fd21
to
7c1049f
Compare
@@ -1155,7 +1155,147 @@ const char* strtok__(const char* s, const char* d, StringBuffer& tok) | |||
return s; | |||
} | |||
|
|||
class CSecureSocketContext : implements ISecureSocketContext, public CInterface | |||
using BIO_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>; |
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.
The code I suggested:
struct BIO_deleter
{
void operator() ( BIO * bio )
{
BIO_free( bio );
}
};
using unique_bioptr = std::unique_ptr<BIO, BIO_deleter>;
avoids the need to pass BIO_free to the constructor of each BIO_ptr.
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, that's a nice approach.
We should keep these helper objects and functions together.
We already have existing helpers in system/security/cryptohelper/cryptocommon.hpp,
both for owned semantics of these ssl objects, and for openssl exception creation.
I'd be happy for those to be switched to using std::unique_ptr in this PR, or it might be best to use them as is for now, and switch their implementation to std::unique_ptr at a later date.
Code changes in commits 5 and 6. |
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.
@mckellyln - looks pretty good, some minor comments, 1 question, and replies to your q's
@@ -271,24 +271,37 @@ int CHttpSoapBinding::HandleSoapRequest(CHttpRequest* request, CHttpResponse* re | |||
return 0; | |||
} | |||
|
|||
|
|||
static IPropertyTree *createSecClientConfig(const char *clientCertPath, const char *clientPrivateKey, const char *caCertsPath, bool acceptSelfSigned) | |||
static IPropertyTree *createSecClientConfig(const char *clientCertFileorBuf, const char *clientPrivKeyFileorBuf, const char *caCertsPathorBuf, bool acceptSelfSigned) |
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.
trivial/pedantic/camelCase: ...Fileor... > ...FileOr..
(and similar elsewhere)
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, changed
throw makeStringExceptionV(-1,"Client private key not found %s.", clientPrivateKey); | ||
|
||
rpc.setClientCertificate(clientCert, clientPrivateKey); |
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.
question: if this code (and similar at other entry points) spotted it was a file, could it load it into a buffer and then unify much of the code it calls to dealing with PEM buffer's only (not files), and therefore simply the code?
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.
In our current kubernetes installations that would work. But in general I'm not sure whether our file handling supports more formats than just PEM. This buffer handling is for PEM content only.
{ | ||
throw MakeStringException(-1, "ctx can't be created"); | ||
} | ||
throw makeStringExceptionV(-1, "ctx can't be created"); |
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.
minor: should be makeStringException
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, changed
{ | ||
char errbuf[512]; | ||
ERR_error_string_n(ERR_get_error(), errbuf, 512); | ||
throw MakeStringException(-1, "error loading certificate chain file %s - %s", certfile, errbuf); | ||
throw makeStringExceptionV(-1, "error loading certificate chain file %s - %s", certFileorBuf, errbuf); |
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.
could use cryptohelper::makeEVPExceptionVA instead of these 3 lines,
and similar in other places below.
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, changed
{ | ||
char errbuf[512]; | ||
ERR_error_string_n(ERR_get_error(), errbuf, 512); | ||
throw makeStringExceptionV(-1, "error loading certificate chain %s", errbuf); |
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.
could use cryptohelper::makeEVPExceptionVA instead of these 3 lines
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, changed
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.
@mckellyln - although squashed, I have scanned this and other changes made in the last commit and looks good.
} | ||
|
||
if(!SSL_CTX_check_private_key(m_ctx)) | ||
if (!SSL_CTX_check_private_key(m_ctx)) | ||
throw makeStringExceptionV(-1, "Private key does not match the certificate public key"); |
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.
minor: should be makeStringException
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, changed
throw MakeStringException(-1, "Private key does not match the certificate public key"); | ||
// can have multiple certs in buffer | ||
if (!loadVerifyLocationsPEMBuffer(m_ctx, caCertsPathorBuf)) | ||
throw makeStringExceptionV(-1, "Error loading CA certificates"); |
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.
minor: should be makeStringException
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, changed
{ | ||
SSL_CTX_free(m_ctx); | ||
} | ||
~CSecureSocketContext() { } |
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.
no need, better to remove it.
m_meth = SSLv23_client_method(); | ||
else | ||
m_meth = SSLv23_server_method(); | ||
// MCK TODO: should we set a default cipherList, as is done in other ctor (below) ? |
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.
looks like we should provide a way for an opional cipherList to be provided via this ctor route too,
and default like the other ctor if not.
and/or could it a method of ISecureSocketContext and (optionally) called to set after construction?
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.
@mckellyln that looks good. A few comments that you may want to address, but I think it can be merged soon/now and other issues tackled later.
info->setProp("certificate", clientCertPath); | ||
if (!isEmptyString(clientPrivateKey)) | ||
info->setProp("privatekey", clientPrivateKey); | ||
if (isPEMBuffer(clientCertFileorBuf)) |
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.
Can this always set "certificate" and then have the PEMbuffer test later? A later clean up PR would be fine.
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, but there is also the pem / @path difference, do we leave that in or also remove ?
system/jlib/jsecrets.cpp
Outdated
@@ -1066,6 +1066,25 @@ const MemoryAttr &getSecretUdpKey(bool required) | |||
return udpKey; | |||
} | |||
|
|||
jlib_decl bool isPEMBuffer(const char *certificate) |
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.
Might be worth coming up with a more intuitive function name (I didn't know what PEM stood for). Something like containsEmbeddedKey()?
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, renamed function.
ea74cd2
to
3565cac
Compare
Squashed commits |
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.
@mckellyln some comments.
@@ -271,6 +271,29 @@ int CHttpSoapBinding::HandleSoapRequest(CHttpRequest* request, CHttpResponse* re | |||
return 0; | |||
} | |||
|
|||
static IPropertyTree *createSecClientConfigBuf(const char *clientCertBuf, const char *clientPrivKeyBuf, const char *caCertsBuf, bool acceptSelfSigned) |
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 is picky and might just be me, but I'd prefer the method name be slightly different.
Like "createInMemorySecClientConfig" or "createBufferedSecClientConfig".. the ending of "ConfigBuf" just implies something specific to me.
if (!cbio) | ||
return false; | ||
|
||
RSA *rsa = PEM_read_bio_RSAPrivateKey(cbio, NULL, 0, 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.
Part of this is probably copy and paste, but new code being added should use nullptr rather than NULL.
|
||
SSL_CTX_set_mode(m_ctx, SSL_CTX_get_mode(m_ctx) | SSL_MODE_AUTO_RETRY); | ||
} | ||
|
||
CSecureSocketContext(const char* certfile, const char* privkeyfile, const char* passphrase, SecureSocketType sockettype) | ||
CSecureSocketContext(StringBuffer& certBuf, StringBuffer& privkeyBuf, const char* passphrase, SecureSocketType sockettype) |
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 the parameters should still just be char pointers and you should find another way of making the constructor signature unique. Like passing flags. That way if the caller is using some other type of string class they can still function.
If you did keep them as StringBuffer, I think the parameters could be const.
certfile = config->queryProp("certificate"); | ||
if (certfile && *certfile) | ||
{ | ||
if (isPEMBuffer(certfile)) |
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.
Looking at this now, I think I can just do what you did when I create these config ptrees. When I have a buffer I can call it certificatebuf, privatekeybuf, pem, etc. You don't need to autodetect the type. It just gets a bit convoluted.
@@ -1871,6 +2122,11 @@ SECURESOCKET_API ISecureSocketContext* createSecureSocketContextEx2(const IPrope | |||
return new securesocket::CSecureSocketContext(config, sockettype); | |||
} | |||
|
|||
SECURESOCKET_API ISecureSocketContext* createSecureSocketContextEx3(StringBuffer& certBuf, StringBuffer& privkeyBuf, const char* passphrase, SecureSocketType sockettype) |
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 we should force these to be passed as StringBuffer. It takes away the flexibility const char * gives is someone is using a different primitive for the strings, or reads them directly into some location.
throw makeStringExceptionV(-1,"Client private key not found %s.", clientPrivateKey); | ||
|
||
rpc.setClientCertificate(clientCert, clientPrivateKey); |
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.
In our current kubernetes installations that would work. But in general I'm not sure whether our file handling supports more formats than just PEM. This buffer handling is for PEM content only.
if (!isEmptyString(clientPrivateKey)) | ||
info->setProp("privatekey", clientPrivateKey); | ||
if (isPEMBuffer(clientCertFileOrBuf)) | ||
info->setProp("certificatebuf", clientCertFileOrBuf); |
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.
Having given it more thought, to support other formats in the future should we call this "certificate_pem" or something similar?
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, renamed. Yes the check for if its embedded could return a type ...
return true; | ||
} | ||
|
||
static bool loadVerifyLocationsPEMBuffer(SSL_CTX *ctx, const char *caCertBuf, int caCertLen=-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 think "verify locations" usually refers to locations on disk, can we change the name to something like "setVerifyCertPEMBuffer" or "setCACertPEMBuffer"?
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, renamed to setVerifyCertPEMBuffer().
throw MakeStringException(-1, "error loading certificate chain file %s - %s", certfile, errbuf); | ||
} | ||
} | ||
const char *certFileOrBuf = config->queryProp("certificatebuf"); |
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.
As mentioned above, I think we should rename these "buf" properties to "certificate_pem" or similiar so we know exactly what they are. For any new formats in the future we can use other names.
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, renamed.
password.set(passphrase); | ||
SSL_CTX_set_default_passwd_cb_userdata(m_ctx, (void*)password.str()); | ||
SSL_CTX_set_default_passwd_cb(m_ctx, pem_passwd_cb); | ||
void setVerifyLocations(const char *caCertsPathOrBuf) |
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.
Perhaps rename this to "setCACerts" or "setVerifyCerts". I think locations is meant to convey files and/or directories.
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, renamed to setVerifyCerts
@afishbeck made changes based on your comments in commit 2a. |
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.
@mckellyln clarified my 1 remaining question.
return false; | ||
} | ||
|
||
X509_STORE *store = SSL_CTX_get_cert_store(ctx); |
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.
@mckellyln what I'm wondering is, because we want only our cacerts, and don't want any default cacerts to remain...
Instead of doing:
X509_STORE *store = SSL_CTX_get_cert_store(ctx);
loop{
X509_STORE_add_cert(store, infoVal->x509);
}
we should do?:
X509_STORE *store = X509_STORE_new();
loop{
X509_STORE_add_cert(store, infoVal->x509);
}
SSL_CTX_set_cert_store(ctx, store); //this will clear (and free) old and add new
ok, good point, I agree we should reset/clear store or check if cert already there, etc. |
@afishbeck like this ? |
} | ||
} | ||
|
||
SSL_CTX_set_cert_store(ctx, store); |
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 happens when the OwnedX509Store above goes out of scope but the pointer has been passed to SSL_CTX_set_cert_store?
Should you do:
SSL_CTX_set_cert_store(ctx, store.getClear());
instead?
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, thank you. It needs to survive.
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.
But then does it get freed when ref count goes to zero ? Or it is already zero at this point ?
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.
When would it ever get freed ? I am thinking we need to free it when we free ctx ?
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.
Maybe a store should be added to CSecureSocketContext ?
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've added a m_store member, if you think this is an ok way to go.
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.
@mckellyln I think this is the difference between SSL_CTX_set_cert_store and SSL_CTX_set1_cert_store. One takes ownership and one increments and decrements the reference count. Either case needs testing to make sure there is no leak or extra free.
I think the only reason to add an m_store is if the store is shared by multiple contexts otherwise it's extra complexity with nothing to gain.
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.
@mckellyln one comment.
a8d5097
to
40fd720
Compare
Having some trouble deciding / understanding the lifetime of a store within a context. Please let me know what you think of adding an m_store member like the last commit ?? |
d51854a
to
40fd720
Compare
ok, removed commit 4a with m_store, so back to original design with the getClear() so it is not freed just after here. |
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.
@mckellyln looks good, and code looks clean. Please squash once Tony has approved and I will merge.
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.
@mckellyln looks good.
40fd720
to
3ff56db
Compare
3ff56db
to
8ceec8c
Compare
Signed-off-by: Mark Kelly <[email protected]>
8ceec8c
to
6425bed
Compare
Squashed and rebased onto candidate-9.4.x |
Type of change:
Checklist:
Smoketest:
Testing: