summaryrefslogtreecommitdiff
path: root/drivers/opus/wincerts.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/opus/wincerts.c')
-rw-r--r--drivers/opus/wincerts.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/drivers/opus/wincerts.c b/drivers/opus/wincerts.c
new file mode 100644
index 0000000000..568a085e43
--- /dev/null
+++ b/drivers/opus/wincerts.c
@@ -0,0 +1,171 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+
+/*This should really be part of OpenSSL, but there's been a patch [1] sitting
+ in their bugtracker for over two years that implements this, without any
+ action, so I'm giving up and re-implementing it locally.
+
+ [1] <http://rt.openssl.org/Ticket/Display.html?id=2158>*/
+
+#ifdef OPUS_HAVE_CONFIG_H
+#include "opus_config.h"
+#endif
+
+#include "internal.h"
+#if defined(OP_ENABLE_HTTP)&&defined(_WIN32)
+/*You must include windows.h before wincrypt.h and x509.h.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get
+ defined properly.*/
+# include <wincrypt.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509.h>
+
+static int op_capi_new(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0,
+ CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG|
+ CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT");
+ if(h_store!=NULL){
+ _lu->method_data=(char *)h_store;
+ return 1;
+ }
+ return 0;
+}
+
+static void op_capi_free(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=(HCERTSTORE)_lu->method_data;
+# if defined(OP_ENABLE_ASSERTIONS)
+ OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG));
+# else
+ CertCloseStore(h_store,0);
+# endif
+}
+
+static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type,
+ X509_NAME *_name,X509_OBJECT *_ret){
+ X509_OBJECT *obj;
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ if(obj!=NULL){
+ _ret->type=obj->type;
+ memcpy(&_ret->data,&obj->data,sizeof(_ret->data));
+ return 1;
+ }
+ return 0;
+}
+
+static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name,
+ X509_OBJECT *_ret){
+ HCERTSTORE h_store;
+ if(_name==NULL)return 0;
+ if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){
+ if(i2d_X509_NAME(_name,NULL)<0)return 0;
+ OP_ASSERT(_name->bytes->length>0);
+ }
+ h_store=(HCERTSTORE)_lu->method_data;
+ switch(_type){
+ case X509_LU_X509:{
+ CERT_NAME_BLOB find_para;
+ PCCERT_CONTEXT cert;
+ X509 *x;
+ int ret;
+ /*Although X509_NAME contains a canon_enc field, that "canonical" [1]
+ encoding was just made up by OpenSSL.
+ It doesn't correspond to any actual standard, and since it drops the
+ initial sequence header, won't be recognized by the Crypto API.
+ The assumption here is that CertFindCertificateInStore() will allow any
+ appropriate variations in the encoding when it does its comparison.
+ This is, however, emphatically not true under Wine, which just compares
+ the encodings with memcmp().
+ Most of the time things work anyway, though, and there isn't really
+ anything we can do to make the situation better.
+
+ [1] A "canonical form" is defined as the one where, if you locked 10
+ mathematicians in a room and asked them to come up with a
+ representation for something, it's the answer that 9 of them would
+ give you back.
+ I don't think OpenSSL's encoding qualifies.*/
+ find_para.cbData=_name->bytes->length;
+ find_para.pbData=(unsigned char *)_name->bytes->data;
+ cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
+ CERT_FIND_SUBJECT_NAME,&find_para,NULL);
+ if(cert==NULL)return 0;
+ x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded,
+ cert->cbCertEncoded);
+ CertFreeCertificateContext(cert);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_cert(_lu->store_ctx,x);
+ X509_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ case X509_LU_CRL:{
+ CERT_INFO cert_info;
+ CERT_CONTEXT find_para;
+ PCCRL_CONTEXT crl;
+ X509_CRL *x;
+ int ret;
+ ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ if(ret>0)return ret;
+ memset(&cert_info,0,sizeof(cert_info));
+ cert_info.Issuer.cbData=_name->bytes->length;
+ cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
+ memset(&find_para,0,sizeof(find_para));
+ find_para.pCertInfo=&cert_info;
+ crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL);
+ if(crl==NULL)return 0;
+ x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded,
+ crl->cbCrlEncoded);
+ CertFreeCRLContext(crl);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_crl(_lu->store_ctx,x);
+ X509_CRL_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ }
+ return 0;
+}
+
+/*This is not const because OpenSSL doesn't allow it, even though it won't
+ write to it.*/
+static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={
+ "Load Crypto API store into cache",
+ op_capi_new,
+ op_capi_free,
+ NULL,
+ NULL,
+ NULL,
+ op_capi_get_by_subject,
+ NULL,
+ NULL,
+ NULL
+};
+
+int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){
+ X509_STORE *store;
+ X509_LOOKUP *lu;
+ /*We intentionally do not add the normal default paths, as they are usually
+ wrong, and are just asking to be used as an exploit vector.*/
+ store=SSL_CTX_get_cert_store(_ssl_ctx);
+ OP_ASSERT(store!=NULL);
+ lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI);
+ if(lu==NULL)return 0;
+ ERR_clear_error();
+ return 1;
+}
+
+#endif