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