117f01e99SJung-uk Kim=pod 217f01e99SJung-uk Kim 317f01e99SJung-uk Kim=encoding UTF-8 417f01e99SJung-uk Kim 517f01e99SJung-uk Kim=head1 NAME 617f01e99SJung-uk Kim 717f01e99SJung-uk Kimproxy-certificates - Proxy certificates in OpenSSL 817f01e99SJung-uk Kim 917f01e99SJung-uk Kim=head1 DESCRIPTION 1017f01e99SJung-uk Kim 1117f01e99SJung-uk KimProxy certificates are defined in RFC 3820. They are used to 1217f01e99SJung-uk Kimextend rights to some other entity (a computer process, typically, or 1317f01e99SJung-uk Kimsometimes to the user itself). This allows the entity to perform 1417f01e99SJung-uk Kimoperations on behalf of the owner of the EE (End Entity) certificate. 1517f01e99SJung-uk Kim 1617f01e99SJung-uk KimThe requirements for a valid proxy certificate are: 1717f01e99SJung-uk Kim 1817f01e99SJung-uk Kim=over 4 1917f01e99SJung-uk Kim 2017f01e99SJung-uk Kim=item * 2117f01e99SJung-uk Kim 2217f01e99SJung-uk KimThey are issued by an End Entity, either a normal EE certificate, or 2317f01e99SJung-uk Kimanother proxy certificate. 2417f01e99SJung-uk Kim 2517f01e99SJung-uk Kim=item * 2617f01e99SJung-uk Kim 2717f01e99SJung-uk KimThey must not have the B<subjectAltName> or B<issuerAltName> 2817f01e99SJung-uk Kimextensions. 2917f01e99SJung-uk Kim 3017f01e99SJung-uk Kim=item * 3117f01e99SJung-uk Kim 3217f01e99SJung-uk KimThey must have the B<proxyCertInfo> extension. 3317f01e99SJung-uk Kim 3417f01e99SJung-uk Kim=item * 3517f01e99SJung-uk Kim 3617f01e99SJung-uk KimThey must have the subject of their issuer, with one B<commonName> 3717f01e99SJung-uk Kimadded. 3817f01e99SJung-uk Kim 3917f01e99SJung-uk Kim=back 4017f01e99SJung-uk Kim 4117f01e99SJung-uk Kim=head2 Enabling proxy certificate verification 4217f01e99SJung-uk Kim 4317f01e99SJung-uk KimOpenSSL expects applications that want to use proxy certificates to be 4417f01e99SJung-uk Kimspecially aware of them, and make that explicit. This is done by 4517f01e99SJung-uk Kimsetting an X509 verification flag: 4617f01e99SJung-uk Kim 4717f01e99SJung-uk Kim X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); 4817f01e99SJung-uk Kim 4917f01e99SJung-uk Kimor 5017f01e99SJung-uk Kim 5117f01e99SJung-uk Kim X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_ALLOW_PROXY_CERTS); 5217f01e99SJung-uk Kim 5317f01e99SJung-uk KimSee L</NOTES> for a discussion on this requirement. 5417f01e99SJung-uk Kim 5517f01e99SJung-uk Kim=head2 Creating proxy certificates 5617f01e99SJung-uk Kim 5717f01e99SJung-uk KimCreating proxy certificates can be done using the L<openssl-x509(1)> 5817f01e99SJung-uk Kimcommand, with some extra extensions: 5917f01e99SJung-uk Kim 60*b077aed3SPierre Pronchery [ proxy ] 6117f01e99SJung-uk Kim # A proxy certificate MUST NEVER be a CA certificate. 6217f01e99SJung-uk Kim basicConstraints = CA:FALSE 6317f01e99SJung-uk Kim # Usual authority key ID 6417f01e99SJung-uk Kim authorityKeyIdentifier = keyid,issuer:always 6517f01e99SJung-uk Kim # The extension which marks this certificate as a proxy 6617f01e99SJung-uk Kim proxyCertInfo = critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB 6717f01e99SJung-uk Kim 6817f01e99SJung-uk KimIt's also possible to specify the proxy extension in a separate section: 6917f01e99SJung-uk Kim 7017f01e99SJung-uk Kim proxyCertInfo = critical,@proxy_ext 7117f01e99SJung-uk Kim 7217f01e99SJung-uk Kim [ proxy_ext ] 7317f01e99SJung-uk Kim language = id-ppl-anyLanguage 7417f01e99SJung-uk Kim pathlen = 0 7517f01e99SJung-uk Kim policy = text:BC 7617f01e99SJung-uk Kim 7717f01e99SJung-uk KimThe policy value has a specific syntax, I<syntag>:I<string>, where the 7817f01e99SJung-uk KimI<syntag> determines what will be done with the string. The following 7917f01e99SJung-uk KimI<syntag>s are recognised: 8017f01e99SJung-uk Kim 8117f01e99SJung-uk Kim=over 4 8217f01e99SJung-uk Kim 8317f01e99SJung-uk Kim=item B<text> 8417f01e99SJung-uk Kim 8517f01e99SJung-uk Kimindicates that the string is a byte sequence, without any encoding: 8617f01e99SJung-uk Kim 8717f01e99SJung-uk Kim policy=text:räksmörgås 8817f01e99SJung-uk Kim 8917f01e99SJung-uk Kim=item B<hex> 9017f01e99SJung-uk Kim 9117f01e99SJung-uk Kimindicates the string is encoded hexadecimal encoded binary data, with 9217f01e99SJung-uk Kimcolons between each byte (every second hex digit): 9317f01e99SJung-uk Kim 9417f01e99SJung-uk Kim policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73 9517f01e99SJung-uk Kim 9617f01e99SJung-uk Kim=item B<file> 9717f01e99SJung-uk Kim 9817f01e99SJung-uk Kimindicates that the text of the policy should be taken from a file. 9917f01e99SJung-uk KimThe string is then a filename. This is useful for policies that are 100*b077aed3SPierre Proncherymore than a few lines, such as XML or other markup. 10117f01e99SJung-uk Kim 10217f01e99SJung-uk Kim=back 10317f01e99SJung-uk Kim 104*b077aed3SPierre ProncheryNote that the proxy policy value is what determines the rights granted 105*b077aed3SPierre Proncheryto the process during the proxy certificate, and it is up to the 10617f01e99SJung-uk Kimapplication to interpret and combine these policies.> 10717f01e99SJung-uk Kim 10817f01e99SJung-uk KimWith a proxy extension, creating a proxy certificate is a matter of 10917f01e99SJung-uk Kimtwo commands: 11017f01e99SJung-uk Kim 11117f01e99SJung-uk Kim openssl req -new -config proxy.cnf \ 11217f01e99SJung-uk Kim -out proxy.req -keyout proxy.key \ 113*b077aed3SPierre Pronchery -subj "/DC=org/DC=openssl/DC=users/CN=proxy" 11417f01e99SJung-uk Kim 11517f01e99SJung-uk Kim openssl x509 -req -CAcreateserial -in proxy.req -out proxy.crt \ 11617f01e99SJung-uk Kim -CA user.crt -CAkey user.key -days 7 \ 117*b077aed3SPierre Pronchery -extfile proxy.cnf -extensions proxy 11817f01e99SJung-uk Kim 11917f01e99SJung-uk KimYou can also create a proxy certificate using another proxy 120*b077aed3SPierre Proncherycertificate as issuer. Note that this example uses a different 121*b077aed3SPierre Proncheryconfiguration section for the proxy extensions: 12217f01e99SJung-uk Kim 12317f01e99SJung-uk Kim openssl req -new -config proxy.cnf \ 12417f01e99SJung-uk Kim -out proxy2.req -keyout proxy2.key \ 125*b077aed3SPierre Pronchery -subj "/DC=org/DC=openssl/DC=users/CN=proxy/CN=proxy 2" 12617f01e99SJung-uk Kim 12717f01e99SJung-uk Kim openssl x509 -req -CAcreateserial -in proxy2.req -out proxy2.crt \ 12817f01e99SJung-uk Kim -CA proxy.crt -CAkey proxy.key -days 7 \ 129*b077aed3SPierre Pronchery -extfile proxy.cnf -extensions proxy_2 13017f01e99SJung-uk Kim 13117f01e99SJung-uk Kim=head2 Using proxy certs in applications 13217f01e99SJung-uk Kim 13317f01e99SJung-uk KimTo interpret proxy policies, the application would normally start with 13417f01e99SJung-uk Kimsome default rights (perhaps none at all), then compute the resulting 13517f01e99SJung-uk Kimrights by checking the rights against the chain of proxy certificates, 13617f01e99SJung-uk Kimuser certificate and CA certificates. 13717f01e99SJung-uk Kim 13817f01e99SJung-uk KimThe complicated part is figuring out how to pass data between your 13917f01e99SJung-uk Kimapplication and the certificate validation procedure. 14017f01e99SJung-uk Kim 14117f01e99SJung-uk KimThe following ingredients are needed for such processing: 14217f01e99SJung-uk Kim 14317f01e99SJung-uk Kim=over 4 14417f01e99SJung-uk Kim 14517f01e99SJung-uk Kim=item * 14617f01e99SJung-uk Kim 14717f01e99SJung-uk Kima callback function that will be called for every certificate being 14817f01e99SJung-uk Kimvalidated. The callback is called several times for each certificate, 14917f01e99SJung-uk Kimso you must be careful to do the proxy policy interpretation at the 15017f01e99SJung-uk Kimright time. You also need to fill in the defaults when the EE 15117f01e99SJung-uk Kimcertificate is checked. 15217f01e99SJung-uk Kim 15317f01e99SJung-uk Kim=item * 15417f01e99SJung-uk Kim 15517f01e99SJung-uk Kima data structure that is shared between your application code and the 15617f01e99SJung-uk Kimcallback. 15717f01e99SJung-uk Kim 15817f01e99SJung-uk Kim=item * 15917f01e99SJung-uk Kim 16017f01e99SJung-uk Kima wrapper function that sets it all up. 16117f01e99SJung-uk Kim 16217f01e99SJung-uk Kim=item * 16317f01e99SJung-uk Kim 16417f01e99SJung-uk Kiman ex_data index function that creates an index into the generic 16517f01e99SJung-uk Kimex_data store that is attached to an X509 validation context. 16617f01e99SJung-uk Kim 16717f01e99SJung-uk Kim=back 16817f01e99SJung-uk Kim 16917f01e99SJung-uk KimThe following skeleton code can be used as a starting point: 17017f01e99SJung-uk Kim 17117f01e99SJung-uk Kim #include <string.h> 17217f01e99SJung-uk Kim #include <netdb.h> 17317f01e99SJung-uk Kim #include <openssl/x509.h> 17417f01e99SJung-uk Kim #include <openssl/x509v3.h> 17517f01e99SJung-uk Kim 17617f01e99SJung-uk Kim #define total_rights 25 17717f01e99SJung-uk Kim 17817f01e99SJung-uk Kim /* 17917f01e99SJung-uk Kim * In this example, I will use a view of granted rights as a bit 18017f01e99SJung-uk Kim * array, one bit for each possible right. 18117f01e99SJung-uk Kim */ 18217f01e99SJung-uk Kim typedef struct your_rights { 18317f01e99SJung-uk Kim unsigned char rights[(total_rights + 7) / 8]; 18417f01e99SJung-uk Kim } YOUR_RIGHTS; 18517f01e99SJung-uk Kim 18617f01e99SJung-uk Kim /* 18717f01e99SJung-uk Kim * The following procedure will create an index for the ex_data 18817f01e99SJung-uk Kim * store in the X509 validation context the first time it's 18917f01e99SJung-uk Kim * called. Subsequent calls will return the same index. 19017f01e99SJung-uk Kim */ 19117f01e99SJung-uk Kim static int get_proxy_auth_ex_data_idx(X509_STORE_CTX *ctx) 19217f01e99SJung-uk Kim { 19317f01e99SJung-uk Kim static volatile int idx = -1; 19417f01e99SJung-uk Kim 19517f01e99SJung-uk Kim if (idx < 0) { 19617f01e99SJung-uk Kim X509_STORE_lock(X509_STORE_CTX_get0_store(ctx)); 19717f01e99SJung-uk Kim if (idx < 0) { 19817f01e99SJung-uk Kim idx = X509_STORE_CTX_get_ex_new_index(0, 19917f01e99SJung-uk Kim "for verify callback", 20017f01e99SJung-uk Kim NULL,NULL,NULL); 20117f01e99SJung-uk Kim } 20217f01e99SJung-uk Kim X509_STORE_unlock(X509_STORE_CTX_get0_store(ctx)); 20317f01e99SJung-uk Kim } 20417f01e99SJung-uk Kim return idx; 20517f01e99SJung-uk Kim } 20617f01e99SJung-uk Kim 20717f01e99SJung-uk Kim /* Callback to be given to the X509 validation procedure. */ 20817f01e99SJung-uk Kim static int verify_callback(int ok, X509_STORE_CTX *ctx) 20917f01e99SJung-uk Kim { 21017f01e99SJung-uk Kim if (ok == 1) { 21117f01e99SJung-uk Kim /* 21217f01e99SJung-uk Kim * It's REALLY important you keep the proxy policy check 21317f01e99SJung-uk Kim * within this section. It's important to know that when 21417f01e99SJung-uk Kim * ok is 1, the certificates are checked from top to 21517f01e99SJung-uk Kim * bottom. You get the CA root first, followed by the 21617f01e99SJung-uk Kim * possible chain of intermediate CAs, followed by the EE 21717f01e99SJung-uk Kim * certificate, followed by the possible proxy 21817f01e99SJung-uk Kim * certificates. 21917f01e99SJung-uk Kim */ 22017f01e99SJung-uk Kim X509 *xs = X509_STORE_CTX_get_current_cert(ctx); 22117f01e99SJung-uk Kim 22217f01e99SJung-uk Kim if (X509_get_extension_flags(xs) & EXFLAG_PROXY) { 22317f01e99SJung-uk Kim YOUR_RIGHTS *rights = 22417f01e99SJung-uk Kim (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, 22517f01e99SJung-uk Kim get_proxy_auth_ex_data_idx(ctx)); 22617f01e99SJung-uk Kim PROXY_CERT_INFO_EXTENSION *pci = 22717f01e99SJung-uk Kim X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL); 22817f01e99SJung-uk Kim 22917f01e99SJung-uk Kim switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) { 23017f01e99SJung-uk Kim case NID_Independent: 23117f01e99SJung-uk Kim /* 23217f01e99SJung-uk Kim * Do whatever you need to grant explicit rights 23317f01e99SJung-uk Kim * to this particular proxy certificate, usually 23417f01e99SJung-uk Kim * by pulling them from some database. If there 23517f01e99SJung-uk Kim * are none to be found, clear all rights (making 23617f01e99SJung-uk Kim * this and any subsequent proxy certificate void 23717f01e99SJung-uk Kim * of any rights). 23817f01e99SJung-uk Kim */ 23917f01e99SJung-uk Kim memset(rights->rights, 0, sizeof(rights->rights)); 24017f01e99SJung-uk Kim break; 24117f01e99SJung-uk Kim case NID_id_ppl_inheritAll: 24217f01e99SJung-uk Kim /* 24317f01e99SJung-uk Kim * This is basically a NOP, we simply let the 24417f01e99SJung-uk Kim * current rights stand as they are. 24517f01e99SJung-uk Kim */ 24617f01e99SJung-uk Kim break; 24717f01e99SJung-uk Kim default: 24817f01e99SJung-uk Kim /* 24917f01e99SJung-uk Kim * This is usually the most complex section of 25017f01e99SJung-uk Kim * code. You really do whatever you want as long 25117f01e99SJung-uk Kim * as you follow RFC 3820. In the example we use 25217f01e99SJung-uk Kim * here, the simplest thing to do is to build 25317f01e99SJung-uk Kim * another, temporary bit array and fill it with 25417f01e99SJung-uk Kim * the rights granted by the current proxy 25517f01e99SJung-uk Kim * certificate, then use it as a mask on the 25617f01e99SJung-uk Kim * accumulated rights bit array, and voilà, you 25717f01e99SJung-uk Kim * now have a new accumulated rights bit array. 25817f01e99SJung-uk Kim */ 25917f01e99SJung-uk Kim { 26017f01e99SJung-uk Kim int i; 26117f01e99SJung-uk Kim YOUR_RIGHTS tmp_rights; 26217f01e99SJung-uk Kim memset(tmp_rights.rights, 0, 26317f01e99SJung-uk Kim sizeof(tmp_rights.rights)); 26417f01e99SJung-uk Kim 26517f01e99SJung-uk Kim /* 26617f01e99SJung-uk Kim * process_rights() is supposed to be a 26717f01e99SJung-uk Kim * procedure that takes a string and its 26817f01e99SJung-uk Kim * length, interprets it and sets the bits 26917f01e99SJung-uk Kim * in the YOUR_RIGHTS pointed at by the 27017f01e99SJung-uk Kim * third argument. 27117f01e99SJung-uk Kim */ 27217f01e99SJung-uk Kim process_rights((char *) pci->proxyPolicy->policy->data, 27317f01e99SJung-uk Kim pci->proxyPolicy->policy->length, 27417f01e99SJung-uk Kim &tmp_rights); 27517f01e99SJung-uk Kim 27617f01e99SJung-uk Kim for(i = 0; i < total_rights / 8; i++) 27717f01e99SJung-uk Kim rights->rights[i] &= tmp_rights.rights[i]; 27817f01e99SJung-uk Kim } 27917f01e99SJung-uk Kim break; 28017f01e99SJung-uk Kim } 28117f01e99SJung-uk Kim PROXY_CERT_INFO_EXTENSION_free(pci); 28217f01e99SJung-uk Kim } else if (!(X509_get_extension_flags(xs) & EXFLAG_CA)) { 28317f01e99SJung-uk Kim /* We have an EE certificate, let's use it to set default! */ 28417f01e99SJung-uk Kim YOUR_RIGHTS *rights = 28517f01e99SJung-uk Kim (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, 28617f01e99SJung-uk Kim get_proxy_auth_ex_data_idx(ctx)); 28717f01e99SJung-uk Kim 28817f01e99SJung-uk Kim /* 28917f01e99SJung-uk Kim * The following procedure finds out what rights the 29017f01e99SJung-uk Kim * owner of the current certificate has, and sets them 29117f01e99SJung-uk Kim * in the YOUR_RIGHTS structure pointed at by the 29217f01e99SJung-uk Kim * second argument. 29317f01e99SJung-uk Kim */ 29417f01e99SJung-uk Kim set_default_rights(xs, rights); 29517f01e99SJung-uk Kim } 29617f01e99SJung-uk Kim } 29717f01e99SJung-uk Kim return ok; 29817f01e99SJung-uk Kim } 29917f01e99SJung-uk Kim 30017f01e99SJung-uk Kim static int my_X509_verify_cert(X509_STORE_CTX *ctx, 30117f01e99SJung-uk Kim YOUR_RIGHTS *needed_rights) 30217f01e99SJung-uk Kim { 30317f01e99SJung-uk Kim int ok; 30417f01e99SJung-uk Kim int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = 30517f01e99SJung-uk Kim X509_STORE_CTX_get_verify_cb(ctx); 30617f01e99SJung-uk Kim YOUR_RIGHTS rights; 30717f01e99SJung-uk Kim 30817f01e99SJung-uk Kim X509_STORE_CTX_set_verify_cb(ctx, verify_callback); 30917f01e99SJung-uk Kim X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(ctx), 31017f01e99SJung-uk Kim &rights); 31117f01e99SJung-uk Kim X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); 31217f01e99SJung-uk Kim ok = X509_verify_cert(ctx); 31317f01e99SJung-uk Kim 31417f01e99SJung-uk Kim if (ok == 1) { 31517f01e99SJung-uk Kim ok = check_needed_rights(rights, needed_rights); 31617f01e99SJung-uk Kim } 31717f01e99SJung-uk Kim 31817f01e99SJung-uk Kim X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb); 31917f01e99SJung-uk Kim 32017f01e99SJung-uk Kim return ok; 32117f01e99SJung-uk Kim } 32217f01e99SJung-uk Kim 32317f01e99SJung-uk KimIf you use SSL or TLS, you can easily set up a callback to have the 32417f01e99SJung-uk Kimcertificates checked properly, using the code above: 32517f01e99SJung-uk Kim 32617f01e99SJung-uk Kim SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, 32717f01e99SJung-uk Kim &needed_rights); 32817f01e99SJung-uk Kim 32917f01e99SJung-uk Kim=head1 NOTES 33017f01e99SJung-uk Kim 33117f01e99SJung-uk KimTo this date, it seems that proxy certificates have only been used in 33217f01e99SJung-uk Kimenvironments that are aware of them, and no one seems to have 33317f01e99SJung-uk Kiminvestigated how they can be used or misused outside of such an 33417f01e99SJung-uk Kimenvironment. 33517f01e99SJung-uk Kim 33617f01e99SJung-uk KimFor that reason, OpenSSL requires that applications aware of proxy 33717f01e99SJung-uk Kimcertificates must also make that explicit. 33817f01e99SJung-uk Kim 33917f01e99SJung-uk KimB<subjectAltName> and B<issuerAltName> are forbidden in proxy 34017f01e99SJung-uk Kimcertificates, and this is enforced in OpenSSL. The subject must be 34117f01e99SJung-uk Kimthe same as the issuer, with one commonName added on. 34217f01e99SJung-uk Kim 34317f01e99SJung-uk Kim=head1 SEE ALSO 34417f01e99SJung-uk Kim 34517f01e99SJung-uk KimL<X509_STORE_CTX_set_flags(3)>, 34617f01e99SJung-uk KimL<X509_STORE_CTX_set_verify_cb(3)>, 34717f01e99SJung-uk KimL<X509_VERIFY_PARAM_set_flags(3)>, 34817f01e99SJung-uk KimL<SSL_CTX_set_cert_verify_callback(3)>, 34917f01e99SJung-uk KimL<openssl-req(1)>, L<openssl-x509(1)>, 35017f01e99SJung-uk KimL<RFC 3820|https://tools.ietf.org/html/rfc3820> 35117f01e99SJung-uk Kim 35217f01e99SJung-uk Kim=head1 COPYRIGHT 35317f01e99SJung-uk Kim 354*b077aed3SPierre ProncheryCopyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. 35517f01e99SJung-uk Kim 35617f01e99SJung-uk KimLicensed under the Apache License 2.0 (the "License"). You may not use 35717f01e99SJung-uk Kimthis file except in compliance with the License. You can obtain a copy 35817f01e99SJung-uk Kimin the file LICENSE in the source distribution or at 35917f01e99SJung-uk KimL<https://www.openssl.org/source/license.html>. 36017f01e99SJung-uk Kim 36117f01e99SJung-uk Kim=cut 362