1*17f01e99SJung-uk Kim=pod 2*17f01e99SJung-uk Kim 3*17f01e99SJung-uk Kim=encoding UTF-8 4*17f01e99SJung-uk Kim 5*17f01e99SJung-uk Kim=head1 NAME 6*17f01e99SJung-uk Kim 7*17f01e99SJung-uk Kimproxy-certificates - Proxy certificates in OpenSSL 8*17f01e99SJung-uk Kim 9*17f01e99SJung-uk Kim=head1 DESCRIPTION 10*17f01e99SJung-uk Kim 11*17f01e99SJung-uk KimProxy certificates are defined in RFC 3820. They are used to 12*17f01e99SJung-uk Kimextend rights to some other entity (a computer process, typically, or 13*17f01e99SJung-uk Kimsometimes to the user itself). This allows the entity to perform 14*17f01e99SJung-uk Kimoperations on behalf of the owner of the EE (End Entity) certificate. 15*17f01e99SJung-uk Kim 16*17f01e99SJung-uk KimThe requirements for a valid proxy certificate are: 17*17f01e99SJung-uk Kim 18*17f01e99SJung-uk Kim=over 4 19*17f01e99SJung-uk Kim 20*17f01e99SJung-uk Kim=item * 21*17f01e99SJung-uk Kim 22*17f01e99SJung-uk KimThey are issued by an End Entity, either a normal EE certificate, or 23*17f01e99SJung-uk Kimanother proxy certificate. 24*17f01e99SJung-uk Kim 25*17f01e99SJung-uk Kim=item * 26*17f01e99SJung-uk Kim 27*17f01e99SJung-uk KimThey must not have the B<subjectAltName> or B<issuerAltName> 28*17f01e99SJung-uk Kimextensions. 29*17f01e99SJung-uk Kim 30*17f01e99SJung-uk Kim=item * 31*17f01e99SJung-uk Kim 32*17f01e99SJung-uk KimThey must have the B<proxyCertInfo> extension. 33*17f01e99SJung-uk Kim 34*17f01e99SJung-uk Kim=item * 35*17f01e99SJung-uk Kim 36*17f01e99SJung-uk KimThey must have the subject of their issuer, with one B<commonName> 37*17f01e99SJung-uk Kimadded. 38*17f01e99SJung-uk Kim 39*17f01e99SJung-uk Kim=back 40*17f01e99SJung-uk Kim 41*17f01e99SJung-uk Kim=head2 Enabling proxy certificate verification 42*17f01e99SJung-uk Kim 43*17f01e99SJung-uk KimOpenSSL expects applications that want to use proxy certificates to be 44*17f01e99SJung-uk Kimspecially aware of them, and make that explicit. This is done by 45*17f01e99SJung-uk Kimsetting an X509 verification flag: 46*17f01e99SJung-uk Kim 47*17f01e99SJung-uk Kim X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); 48*17f01e99SJung-uk Kim 49*17f01e99SJung-uk Kimor 50*17f01e99SJung-uk Kim 51*17f01e99SJung-uk Kim X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_ALLOW_PROXY_CERTS); 52*17f01e99SJung-uk Kim 53*17f01e99SJung-uk KimSee L</NOTES> for a discussion on this requirement. 54*17f01e99SJung-uk Kim 55*17f01e99SJung-uk Kim=head2 Creating proxy certificates 56*17f01e99SJung-uk Kim 57*17f01e99SJung-uk KimCreating proxy certificates can be done using the L<openssl-x509(1)> 58*17f01e99SJung-uk Kimcommand, with some extra extensions: 59*17f01e99SJung-uk Kim 60*17f01e99SJung-uk Kim [ v3_proxy ] 61*17f01e99SJung-uk Kim # A proxy certificate MUST NEVER be a CA certificate. 62*17f01e99SJung-uk Kim basicConstraints=CA:FALSE 63*17f01e99SJung-uk Kim 64*17f01e99SJung-uk Kim # Usual authority key ID 65*17f01e99SJung-uk Kim authorityKeyIdentifier=keyid,issuer:always 66*17f01e99SJung-uk Kim 67*17f01e99SJung-uk Kim # The extension which marks this certificate as a proxy 68*17f01e99SJung-uk Kim proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB 69*17f01e99SJung-uk Kim 70*17f01e99SJung-uk KimIt's also possible to specify the proxy extension in a separate section: 71*17f01e99SJung-uk Kim 72*17f01e99SJung-uk Kim proxyCertInfo=critical,@proxy_ext 73*17f01e99SJung-uk Kim 74*17f01e99SJung-uk Kim [ proxy_ext ] 75*17f01e99SJung-uk Kim language=id-ppl-anyLanguage 76*17f01e99SJung-uk Kim pathlen=0 77*17f01e99SJung-uk Kim policy=text:BC 78*17f01e99SJung-uk Kim 79*17f01e99SJung-uk KimThe policy value has a specific syntax, I<syntag>:I<string>, where the 80*17f01e99SJung-uk KimI<syntag> determines what will be done with the string. The following 81*17f01e99SJung-uk KimI<syntag>s are recognised: 82*17f01e99SJung-uk Kim 83*17f01e99SJung-uk Kim=over 4 84*17f01e99SJung-uk Kim 85*17f01e99SJung-uk Kim=item B<text> 86*17f01e99SJung-uk Kim 87*17f01e99SJung-uk Kimindicates that the string is a byte sequence, without any encoding: 88*17f01e99SJung-uk Kim 89*17f01e99SJung-uk Kim policy=text:räksmörgås 90*17f01e99SJung-uk Kim 91*17f01e99SJung-uk Kim=item B<hex> 92*17f01e99SJung-uk Kim 93*17f01e99SJung-uk Kimindicates the string is encoded hexadecimal encoded binary data, with 94*17f01e99SJung-uk Kimcolons between each byte (every second hex digit): 95*17f01e99SJung-uk Kim 96*17f01e99SJung-uk Kim policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73 97*17f01e99SJung-uk Kim 98*17f01e99SJung-uk Kim=item B<file> 99*17f01e99SJung-uk Kim 100*17f01e99SJung-uk Kimindicates that the text of the policy should be taken from a file. 101*17f01e99SJung-uk KimThe string is then a filename. This is useful for policies that are 102*17f01e99SJung-uk Kimlarge (more than a few lines, e.g. XML documents). 103*17f01e99SJung-uk Kim 104*17f01e99SJung-uk Kim=back 105*17f01e99SJung-uk Kim 106*17f01e99SJung-uk KimI<NOTE: The proxy policy value is what determines the rights granted 107*17f01e99SJung-uk Kimto the process during the proxy certificate. It's up to the 108*17f01e99SJung-uk Kimapplication to interpret and combine these policies.> 109*17f01e99SJung-uk Kim 110*17f01e99SJung-uk KimWith a proxy extension, creating a proxy certificate is a matter of 111*17f01e99SJung-uk Kimtwo commands: 112*17f01e99SJung-uk Kim 113*17f01e99SJung-uk Kim openssl req -new -config proxy.cnf \ 114*17f01e99SJung-uk Kim -out proxy.req -keyout proxy.key \ 115*17f01e99SJung-uk Kim -subj "/DC=org/DC=openssl/DC=users/CN=proxy 1" 116*17f01e99SJung-uk Kim 117*17f01e99SJung-uk Kim openssl x509 -req -CAcreateserial -in proxy.req -out proxy.crt \ 118*17f01e99SJung-uk Kim -CA user.crt -CAkey user.key -days 7 \ 119*17f01e99SJung-uk Kim -extfile proxy.cnf -extensions v3_proxy1 120*17f01e99SJung-uk Kim 121*17f01e99SJung-uk KimYou can also create a proxy certificate using another proxy 122*17f01e99SJung-uk Kimcertificate as issuer (note: using a different configuration 123*17f01e99SJung-uk Kimsection for the proxy extensions): 124*17f01e99SJung-uk Kim 125*17f01e99SJung-uk Kim openssl req -new -config proxy.cnf \ 126*17f01e99SJung-uk Kim -out proxy2.req -keyout proxy2.key \ 127*17f01e99SJung-uk Kim -subj "/DC=org/DC=openssl/DC=users/CN=proxy 1/CN=proxy 2" 128*17f01e99SJung-uk Kim 129*17f01e99SJung-uk Kim openssl x509 -req -CAcreateserial -in proxy2.req -out proxy2.crt \ 130*17f01e99SJung-uk Kim -CA proxy.crt -CAkey proxy.key -days 7 \ 131*17f01e99SJung-uk Kim -extfile proxy.cnf -extensions v3_proxy2 132*17f01e99SJung-uk Kim 133*17f01e99SJung-uk Kim=head2 Using proxy certs in applications 134*17f01e99SJung-uk Kim 135*17f01e99SJung-uk KimTo interpret proxy policies, the application would normally start with 136*17f01e99SJung-uk Kimsome default rights (perhaps none at all), then compute the resulting 137*17f01e99SJung-uk Kimrights by checking the rights against the chain of proxy certificates, 138*17f01e99SJung-uk Kimuser certificate and CA certificates. 139*17f01e99SJung-uk Kim 140*17f01e99SJung-uk KimThe complicated part is figuring out how to pass data between your 141*17f01e99SJung-uk Kimapplication and the certificate validation procedure. 142*17f01e99SJung-uk Kim 143*17f01e99SJung-uk KimThe following ingredients are needed for such processing: 144*17f01e99SJung-uk Kim 145*17f01e99SJung-uk Kim=over 4 146*17f01e99SJung-uk Kim 147*17f01e99SJung-uk Kim=item * 148*17f01e99SJung-uk Kim 149*17f01e99SJung-uk Kima callback function that will be called for every certificate being 150*17f01e99SJung-uk Kimvalidated. The callback is called several times for each certificate, 151*17f01e99SJung-uk Kimso you must be careful to do the proxy policy interpretation at the 152*17f01e99SJung-uk Kimright time. You also need to fill in the defaults when the EE 153*17f01e99SJung-uk Kimcertificate is checked. 154*17f01e99SJung-uk Kim 155*17f01e99SJung-uk Kim=item * 156*17f01e99SJung-uk Kim 157*17f01e99SJung-uk Kima data structure that is shared between your application code and the 158*17f01e99SJung-uk Kimcallback. 159*17f01e99SJung-uk Kim 160*17f01e99SJung-uk Kim=item * 161*17f01e99SJung-uk Kim 162*17f01e99SJung-uk Kima wrapper function that sets it all up. 163*17f01e99SJung-uk Kim 164*17f01e99SJung-uk Kim=item * 165*17f01e99SJung-uk Kim 166*17f01e99SJung-uk Kiman ex_data index function that creates an index into the generic 167*17f01e99SJung-uk Kimex_data store that is attached to an X509 validation context. 168*17f01e99SJung-uk Kim 169*17f01e99SJung-uk Kim=back 170*17f01e99SJung-uk Kim 171*17f01e99SJung-uk KimThe following skeleton code can be used as a starting point: 172*17f01e99SJung-uk Kim 173*17f01e99SJung-uk Kim #include <string.h> 174*17f01e99SJung-uk Kim #include <netdb.h> 175*17f01e99SJung-uk Kim #include <openssl/x509.h> 176*17f01e99SJung-uk Kim #include <openssl/x509v3.h> 177*17f01e99SJung-uk Kim 178*17f01e99SJung-uk Kim #define total_rights 25 179*17f01e99SJung-uk Kim 180*17f01e99SJung-uk Kim /* 181*17f01e99SJung-uk Kim * In this example, I will use a view of granted rights as a bit 182*17f01e99SJung-uk Kim * array, one bit for each possible right. 183*17f01e99SJung-uk Kim */ 184*17f01e99SJung-uk Kim typedef struct your_rights { 185*17f01e99SJung-uk Kim unsigned char rights[(total_rights + 7) / 8]; 186*17f01e99SJung-uk Kim } YOUR_RIGHTS; 187*17f01e99SJung-uk Kim 188*17f01e99SJung-uk Kim /* 189*17f01e99SJung-uk Kim * The following procedure will create an index for the ex_data 190*17f01e99SJung-uk Kim * store in the X509 validation context the first time it's 191*17f01e99SJung-uk Kim * called. Subsequent calls will return the same index. 192*17f01e99SJung-uk Kim */ 193*17f01e99SJung-uk Kim static int get_proxy_auth_ex_data_idx(X509_STORE_CTX *ctx) 194*17f01e99SJung-uk Kim { 195*17f01e99SJung-uk Kim static volatile int idx = -1; 196*17f01e99SJung-uk Kim 197*17f01e99SJung-uk Kim if (idx < 0) { 198*17f01e99SJung-uk Kim X509_STORE_lock(X509_STORE_CTX_get0_store(ctx)); 199*17f01e99SJung-uk Kim if (idx < 0) { 200*17f01e99SJung-uk Kim idx = X509_STORE_CTX_get_ex_new_index(0, 201*17f01e99SJung-uk Kim "for verify callback", 202*17f01e99SJung-uk Kim NULL,NULL,NULL); 203*17f01e99SJung-uk Kim } 204*17f01e99SJung-uk Kim X509_STORE_unlock(X509_STORE_CTX_get0_store(ctx)); 205*17f01e99SJung-uk Kim } 206*17f01e99SJung-uk Kim return idx; 207*17f01e99SJung-uk Kim } 208*17f01e99SJung-uk Kim 209*17f01e99SJung-uk Kim /* Callback to be given to the X509 validation procedure. */ 210*17f01e99SJung-uk Kim static int verify_callback(int ok, X509_STORE_CTX *ctx) 211*17f01e99SJung-uk Kim { 212*17f01e99SJung-uk Kim if (ok == 1) { 213*17f01e99SJung-uk Kim /* 214*17f01e99SJung-uk Kim * It's REALLY important you keep the proxy policy check 215*17f01e99SJung-uk Kim * within this section. It's important to know that when 216*17f01e99SJung-uk Kim * ok is 1, the certificates are checked from top to 217*17f01e99SJung-uk Kim * bottom. You get the CA root first, followed by the 218*17f01e99SJung-uk Kim * possible chain of intermediate CAs, followed by the EE 219*17f01e99SJung-uk Kim * certificate, followed by the possible proxy 220*17f01e99SJung-uk Kim * certificates. 221*17f01e99SJung-uk Kim */ 222*17f01e99SJung-uk Kim X509 *xs = X509_STORE_CTX_get_current_cert(ctx); 223*17f01e99SJung-uk Kim 224*17f01e99SJung-uk Kim if (X509_get_extension_flags(xs) & EXFLAG_PROXY) { 225*17f01e99SJung-uk Kim YOUR_RIGHTS *rights = 226*17f01e99SJung-uk Kim (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, 227*17f01e99SJung-uk Kim get_proxy_auth_ex_data_idx(ctx)); 228*17f01e99SJung-uk Kim PROXY_CERT_INFO_EXTENSION *pci = 229*17f01e99SJung-uk Kim X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL); 230*17f01e99SJung-uk Kim 231*17f01e99SJung-uk Kim switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) { 232*17f01e99SJung-uk Kim case NID_Independent: 233*17f01e99SJung-uk Kim /* 234*17f01e99SJung-uk Kim * Do whatever you need to grant explicit rights 235*17f01e99SJung-uk Kim * to this particular proxy certificate, usually 236*17f01e99SJung-uk Kim * by pulling them from some database. If there 237*17f01e99SJung-uk Kim * are none to be found, clear all rights (making 238*17f01e99SJung-uk Kim * this and any subsequent proxy certificate void 239*17f01e99SJung-uk Kim * of any rights). 240*17f01e99SJung-uk Kim */ 241*17f01e99SJung-uk Kim memset(rights->rights, 0, sizeof(rights->rights)); 242*17f01e99SJung-uk Kim break; 243*17f01e99SJung-uk Kim case NID_id_ppl_inheritAll: 244*17f01e99SJung-uk Kim /* 245*17f01e99SJung-uk Kim * This is basically a NOP, we simply let the 246*17f01e99SJung-uk Kim * current rights stand as they are. 247*17f01e99SJung-uk Kim */ 248*17f01e99SJung-uk Kim break; 249*17f01e99SJung-uk Kim default: 250*17f01e99SJung-uk Kim /* 251*17f01e99SJung-uk Kim * This is usually the most complex section of 252*17f01e99SJung-uk Kim * code. You really do whatever you want as long 253*17f01e99SJung-uk Kim * as you follow RFC 3820. In the example we use 254*17f01e99SJung-uk Kim * here, the simplest thing to do is to build 255*17f01e99SJung-uk Kim * another, temporary bit array and fill it with 256*17f01e99SJung-uk Kim * the rights granted by the current proxy 257*17f01e99SJung-uk Kim * certificate, then use it as a mask on the 258*17f01e99SJung-uk Kim * accumulated rights bit array, and voilà, you 259*17f01e99SJung-uk Kim * now have a new accumulated rights bit array. 260*17f01e99SJung-uk Kim */ 261*17f01e99SJung-uk Kim { 262*17f01e99SJung-uk Kim int i; 263*17f01e99SJung-uk Kim YOUR_RIGHTS tmp_rights; 264*17f01e99SJung-uk Kim memset(tmp_rights.rights, 0, 265*17f01e99SJung-uk Kim sizeof(tmp_rights.rights)); 266*17f01e99SJung-uk Kim 267*17f01e99SJung-uk Kim /* 268*17f01e99SJung-uk Kim * process_rights() is supposed to be a 269*17f01e99SJung-uk Kim * procedure that takes a string and its 270*17f01e99SJung-uk Kim * length, interprets it and sets the bits 271*17f01e99SJung-uk Kim * in the YOUR_RIGHTS pointed at by the 272*17f01e99SJung-uk Kim * third argument. 273*17f01e99SJung-uk Kim */ 274*17f01e99SJung-uk Kim process_rights((char *) pci->proxyPolicy->policy->data, 275*17f01e99SJung-uk Kim pci->proxyPolicy->policy->length, 276*17f01e99SJung-uk Kim &tmp_rights); 277*17f01e99SJung-uk Kim 278*17f01e99SJung-uk Kim for(i = 0; i < total_rights / 8; i++) 279*17f01e99SJung-uk Kim rights->rights[i] &= tmp_rights.rights[i]; 280*17f01e99SJung-uk Kim } 281*17f01e99SJung-uk Kim break; 282*17f01e99SJung-uk Kim } 283*17f01e99SJung-uk Kim PROXY_CERT_INFO_EXTENSION_free(pci); 284*17f01e99SJung-uk Kim } else if (!(X509_get_extension_flags(xs) & EXFLAG_CA)) { 285*17f01e99SJung-uk Kim /* We have an EE certificate, let's use it to set default! */ 286*17f01e99SJung-uk Kim YOUR_RIGHTS *rights = 287*17f01e99SJung-uk Kim (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, 288*17f01e99SJung-uk Kim get_proxy_auth_ex_data_idx(ctx)); 289*17f01e99SJung-uk Kim 290*17f01e99SJung-uk Kim /* 291*17f01e99SJung-uk Kim * The following procedure finds out what rights the 292*17f01e99SJung-uk Kim * owner of the current certificate has, and sets them 293*17f01e99SJung-uk Kim * in the YOUR_RIGHTS structure pointed at by the 294*17f01e99SJung-uk Kim * second argument. 295*17f01e99SJung-uk Kim */ 296*17f01e99SJung-uk Kim set_default_rights(xs, rights); 297*17f01e99SJung-uk Kim } 298*17f01e99SJung-uk Kim } 299*17f01e99SJung-uk Kim return ok; 300*17f01e99SJung-uk Kim } 301*17f01e99SJung-uk Kim 302*17f01e99SJung-uk Kim static int my_X509_verify_cert(X509_STORE_CTX *ctx, 303*17f01e99SJung-uk Kim YOUR_RIGHTS *needed_rights) 304*17f01e99SJung-uk Kim { 305*17f01e99SJung-uk Kim int ok; 306*17f01e99SJung-uk Kim int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = 307*17f01e99SJung-uk Kim X509_STORE_CTX_get_verify_cb(ctx); 308*17f01e99SJung-uk Kim YOUR_RIGHTS rights; 309*17f01e99SJung-uk Kim 310*17f01e99SJung-uk Kim X509_STORE_CTX_set_verify_cb(ctx, verify_callback); 311*17f01e99SJung-uk Kim X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(ctx), 312*17f01e99SJung-uk Kim &rights); 313*17f01e99SJung-uk Kim X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); 314*17f01e99SJung-uk Kim ok = X509_verify_cert(ctx); 315*17f01e99SJung-uk Kim 316*17f01e99SJung-uk Kim if (ok == 1) { 317*17f01e99SJung-uk Kim ok = check_needed_rights(rights, needed_rights); 318*17f01e99SJung-uk Kim } 319*17f01e99SJung-uk Kim 320*17f01e99SJung-uk Kim X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb); 321*17f01e99SJung-uk Kim 322*17f01e99SJung-uk Kim return ok; 323*17f01e99SJung-uk Kim } 324*17f01e99SJung-uk Kim 325*17f01e99SJung-uk KimIf you use SSL or TLS, you can easily set up a callback to have the 326*17f01e99SJung-uk Kimcertificates checked properly, using the code above: 327*17f01e99SJung-uk Kim 328*17f01e99SJung-uk Kim SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, 329*17f01e99SJung-uk Kim &needed_rights); 330*17f01e99SJung-uk Kim 331*17f01e99SJung-uk Kim=head1 NOTES 332*17f01e99SJung-uk Kim 333*17f01e99SJung-uk KimTo this date, it seems that proxy certificates have only been used in 334*17f01e99SJung-uk Kimenvironments that are aware of them, and no one seems to have 335*17f01e99SJung-uk Kiminvestigated how they can be used or misused outside of such an 336*17f01e99SJung-uk Kimenvironment. 337*17f01e99SJung-uk Kim 338*17f01e99SJung-uk KimFor that reason, OpenSSL requires that applications aware of proxy 339*17f01e99SJung-uk Kimcertificates must also make that explicit. 340*17f01e99SJung-uk Kim 341*17f01e99SJung-uk KimB<subjectAltName> and B<issuerAltName> are forbidden in proxy 342*17f01e99SJung-uk Kimcertificates, and this is enforced in OpenSSL. The subject must be 343*17f01e99SJung-uk Kimthe same as the issuer, with one commonName added on. 344*17f01e99SJung-uk Kim 345*17f01e99SJung-uk Kim=head1 SEE ALSO 346*17f01e99SJung-uk Kim 347*17f01e99SJung-uk KimL<X509_STORE_CTX_set_flags(3)>, 348*17f01e99SJung-uk KimL<X509_STORE_CTX_set_verify_cb(3)>, 349*17f01e99SJung-uk KimL<X509_VERIFY_PARAM_set_flags(3)>, 350*17f01e99SJung-uk KimL<SSL_CTX_set_cert_verify_callback(3)>, 351*17f01e99SJung-uk KimL<openssl-req(1)>, L<openssl-x509(1)>, 352*17f01e99SJung-uk KimL<RFC 3820|https://tools.ietf.org/html/rfc3820> 353*17f01e99SJung-uk Kim 354*17f01e99SJung-uk Kim=head1 COPYRIGHT 355*17f01e99SJung-uk Kim 356*17f01e99SJung-uk KimCopyright 2019 The OpenSSL Project Authors. All Rights Reserved. 357*17f01e99SJung-uk Kim 358*17f01e99SJung-uk KimLicensed under the Apache License 2.0 (the "License"). You may not use 359*17f01e99SJung-uk Kimthis file except in compliance with the License. You can obtain a copy 360*17f01e99SJung-uk Kimin the file LICENSE in the source distribution or at 361*17f01e99SJung-uk KimL<https://www.openssl.org/source/license.html>. 362*17f01e99SJung-uk Kim 363*17f01e99SJung-uk Kim=cut 364