Correct environment variable is OPENSSL_ALLOW_PROXY_CERTS.
[openssl.git] / doc / HOWTO / proxy_certificates.txt
1 <DRAFT!>
2                         HOWTO proxy certificates
3
4 0. WARNING
5
6 NONE OF THE CODE PRESENTED HERE HAVE BEEN CHECKED!  They are just an
7 example to show you how things can be done.  There may be typos or
8 type conflicts, and you will have to resolve them.
9
10 1. Introduction
11
12 Proxy certificates are defined in RFC 3820.  They are really usual
13 certificates with the mandatory extension proxyCertInfo.
14
15 Proxy certificates are issued by an End Entity (typically a user),
16 either directly with the EE certificate as issuing certificate, or by
17 extension through an already issued proxy certificate..  They are used
18 to extend rights to some other entity (a computer process, typically,
19 or sometimes to the user itself), so it can perform operations in the
20 name of the owner of the EE certificate.
21
22 See http://www.ietf.org/rfc/rfc3820.txt for more information.
23
24
25 2. A warning about proxy certificates
26
27 Noone seems to have tested proxy certificates with security in mind.
28 Basically, to this date, it seems that proxy certificates have only
29 been used in a world that's highly aware of them.  What would happen
30 if an unsuspecting application is to validate a chain of certificates
31 that contains proxy certificates?  It would usually consider the leaf
32 to be the certificate to check for authorisation data, and since proxy
33 certificates are controlled by the EE certificate owner alone, it's
34 would be normal to consider what the EE certificate owner could do
35 with them.
36
37 subjectAltName and issuerAltName are forbidden in proxy certificates,
38 and this is enforced in OpenSSL.  The subject must be the same as the
39 issuer, with one commonName added on.
40
41 Possible threats are, as far as has been imagined so far:
42
43  - impersonation through commonName (think server certificates).
44  - use of additional extensions, possibly non-standard ones used in
45    certain environments, that would grant extra or different
46    authorisation rights.
47
48 For this reason, OpenSSL requires that the use of proxy certificates
49 be explicitely allowed.  Currently, this can be done using the
50 following methods:
51
52  - if the application calls X509_verify_cert() itself, it can do the
53    following prior to that call (ctx is the pointer passed in the call
54    to X509_verify_cert()):
55
56         X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
57
58  - in all other cases, proxy certificate validation can be enabled
59    before starting the application by setting the envirnoment variable
60    OPENSSL_ALLOW_PROXY_CERTS with some non-empty value.
61
62 There are thoughts to allow proxy certificates with a line in the
63 default openssl.cnf, but that's still in the future.
64
65
66 3. How to create proxy cerificates
67
68 It's quite easy to create proxy certificates, by taking advantage of
69 the lack of checks of the 'openssl x509' application (*ahem*).  But
70 first, you need to create a configuration section that contains a
71 definition of the proxyCertInfo extension, a little like this:
72
73   [ v3_proxy ]
74   # A proxy certificate MUST NEVER be a CA certificate.
75   basicConstraints=CA:FALSE
76
77   # Usual authority key ID
78   authorityKeyIdentifier=keyid,issuer:always
79
80   # Now, for the extension that marks this certificate as a proxy one
81   proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB
82
83 It's also possible to give the proxy extension in a separate section:
84
85   proxyCertInfo=critical,@proxy_ext
86
87   [ proxy_ext ]
88   language=id-ppl-anyLanguage
89   pathlen=0
90   policy=text:BC
91
92 The policy value has a specific syntax, {syntag}:{string}, where the
93 syntag determines what will be done with the string.  The recognised
94 syntags are as follows:
95
96   text  indicates that the string is simply the bytes, not
97         encoded in any kind of way:
98
99                 policy=text:räksmörgås
100
101         Previous versions of this design had a specific tag
102         for UTF-8 text.  However, since the bytes are copied
103         as-is anyway, there's no need for it.  Instead, use
104         the text: tag, like this:
105
106                 policy=text:räksmörgås
107
108   hex   indicates the string is encoded in hex, with colons
109         between each byte (every second hex digit):
110
111                 policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73
112
113         Previous versions of this design had a tag to insert a
114         complete DER blob.  However, the only legal use for
115         this would be to surround the bytes that would go with
116         the hex: tag with what's needed to construct a correct
117         OCTET STRING.  Since hex: does that, the DER tag felt
118         superfluous, and was therefore removed.
119
120   file  indicates that the text of the policy should really be
121         taken from a file.  The string is then really a file
122         name.  This is useful for policies that are large
123         (more than a few of lines) XML documents, for example.
124
125 The 'policy' setting can be split up in multiple lines like this:
126
127   0.policy=This is
128   1.polisy= a multi-
129   2.policy=line policy.
130
131 NOTE: the proxy policy value is the part that determines the rights
132 granted to the process using the proxy certificate.  The value is
133 completely dependent on the application reading and interpretting it!
134
135 Now that you have created an extension section for your proxy
136 certificate, you can now easily create a proxy certificate like this:
137
138   openssl req -new -config openssl.cnf \
139           -out proxy.req -keyout proxy.key
140   openssl x509 -req -CAcreateserial -in proxy.req -days 7 \
141           -out proxy.crt -CA user.crt -CAkey user.key \
142           -extfile openssl.cnf -extensions v3_proxy
143
144 It's just as easy to create a proxy certificate using another proxy
145 certificate as issuer (note that I'm using a different configuration
146 section for it):
147
148   openssl req -new -config openssl.cnf \
149           -out proxy2.req -keyout proxy2.key
150   openssl x509 -req -CAcreateserial -in proxy2.req -days 7 \
151           -out proxy2.crt -CA proxy.crt -CAkey proxy.key \
152           -extfile openssl.cnf -extensions v3_proxy2
153
154
155 4. How to have your application interpret the policy?
156
157 The basic way to interpret proxy policies is to prepare some default
158 rights, then do a check of the proxy certificate against the a chain
159 of proxy certificates, user certificate and CA certificates, and see
160 what rights came out by the end.  Sounds easy, huh?  It almost is.
161
162 The slightly complicated part is how to pass data between your
163 application and the certificate validation procedure.
164
165 You need the following ingredients:
166
167  - a callback routing that will be called for every certificate that's
168    validated.  It will be called several times for each certificates,
169    so you must be attentive to when it's a good time to do the proxy
170    policy interpretation and check, as well as to fill in the defaults
171    when the EE certificate is checked.
172
173  - a structure of data that's shared between your application code and
174    the callback.
175
176  - a wrapper function that sets it all up.
177
178  - an ex_data index function that creates an index into the generic
179    ex_data store that's attached to an X509 validation context.
180
181 This is some cookbook code for you to fill in:
182
183   /* In this example, I will use a view of granted rights as a bit
184      array, one bit for each possible right.  */
185   typedef struct your_rights {
186     unsigned char rights[total_rights / 8];
187   } YOUR_RIGHTS;
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 called.
191      Subsequent calls will return the same index.  */
192   static int get_proxy_auth_ex_data_idx(void)
193   {
194     static volatile int idx = -1;
195     if (idx < 0)
196       {
197         CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
198         if (idx < 0)
199           {
200             idx = X509_STORE_CTX_get_ex_new_index(0,
201                                                   "for verify callback",
202                                                   NULL,NULL,NULL);
203           }
204         CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
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) /* It's REALLY important you keep the proxy policy
213                     check within this secion.  It's important to know
214                     that when ok is 1, the certificates are checked
215                     from top to bottom.  You get the CA root first,
216                     followed by the possible chain of intermediate
217                     CAs, followed by the EE certificate, followed by
218                     the possible proxy certificates.  */
219       {
220         X509 *xs = ctx->current_cert;
221
222         if (xs->ex_flags & EXFLAG_PROXY)
223           {
224             YOUR_RIGHTS *rights =
225               (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
226                 get_proxy_auth_ex_data_idx());
227             PROXY_CERT_INFO_EXTENSION *pci =
228               X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL);
229
230             switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage))
231               {
232               case NID_Independent:
233                 /* Do whatever you need to grant explicit rights to
234                    this particular proxy certificate, usually by
235                    pulling them from some database.  If there are none
236                    to be found, clear all rights (making this and any
237                    subsequent proxy certificate void of any rights).
238                 */
239                 memset(rights->rights, 0, sizeof(rights->rights));
240                 break;
241               case NID_id_ppl_inheritAll:
242                 /* This is basically a NOP, we simply let the current
243                    rights stand as they are. */
244                 break;
245               default:
246                 /* This is usually the most complex section of code.
247                    You really do whatever you want as long as you
248                    follow RFC 3820.  In the example we use here, the
249                    simplest thing to do is to build another, temporary
250                    bit array and fill it with the rights granted by
251                    the current proxy certificate, then use it as a
252                    mask on the accumulated rights bit array, and
253                    voilà, you now have a new accumulated rights bit
254                    array.  */
255                 {
256                   int i;
257                   YOUR_RIGHTS tmp_rights;
258                   memset(tmp_rights.rights, 0, sizeof(tmp_rights.rights));
259
260                   /* process_rights() is supposed to be a procedure
261                      that takes a string and it's length, interprets
262                      it and sets the bits in the YOUR_RIGHTS pointed
263                      at by the third argument.  */
264                   process_rights((char *) pci->proxyPolicy->policy->data,
265                                  pci->proxyPolicy->policy->length,
266                                  &tmp_rights);
267
268                   for(i = 0; i < total_rights / 8; i++)
269                     rights->rights[i] &= tmp_rights.rights[i];
270                 }
271                 break;
272               }
273             PROXY_CERT_INFO_EXTENSION_free(pci);
274           }
275         else if (!(xs->ex_flags & EXFLAG_CA))
276           {
277             /* We have a EE certificate, let's use it to set default!
278             */
279             YOUR_RIGHTS *rights =
280               (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
281                 get_proxy_auth_ex_data_idx());
282
283             /* The following procedure finds out what rights the owner
284                of the current certificate has, and sets them in the
285                YOUR_RIGHTS structure pointed at by the second
286                argument.  */
287             set_default_rights(xs, rights);
288           }
289       }
290     return ok;
291   }
292
293   static int my_X509_verify_cert(X509_STORE_CTX *ctx,
294                                  YOUR_RIGHTS *needed_rights)
295   {
296     int i;
297     int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = ctx->verify_cb;
298     YOUR_RIGHTS rights;
299
300     X509_STORE_CTX_set_verify_cb(ctx, verify_callback);
301     X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(), &rights);
302     X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
303     ok = X509_verify_cert(ctx);
304
305     if (ok == 1)
306       {
307         ok = check_needed_rights(rights, needed_rights);
308       }
309
310     X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb);
311
312     return ok;
313   }
314
315 If you use SSL or TLS, you can easily set up a callback to have the
316 certificates checked properly, using the code above:
317
318   SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, &needed_rights);
319
320
321 -- 
322 Richard Levitte