Added HOWTO about proxy certificates.
[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. How to create proxy cerificates
26
27 It's quite easy to create proxy certificates, by taking advantage of
28 the lack of checks of the 'openssl x509' application (*ahem*).  But
29 first, you need to create a configuration section that contains a
30 definition of the proxyCertInfo extension, a little like this:
31
32   [ v3_proxy ]
33   # A proxy certificate MUST NEVER be a CA certificate.
34   basicConstraints=CA:FALSE
35
36   # Usual authority key ID
37   authorityKeyIdentifier=keyid,issuer:always
38
39   # Now, for the extension that marks this certificate as a proxy one
40   proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB
41
42 It's also possible to give the proxy extension in a separate section:
43
44   proxyCertInfo=critical,@proxy_ext
45
46   [ proxy_ext ]
47   language=id-ppl-anyLanguage
48   pathlen=0
49   policy=text:BC
50
51 The policy value has a specific syntax, {syntag}:{string}, where the
52 syntag determines what will be done with the string.  The recognised
53 syntags are as follows:
54
55   text  indicates that the string is simply the bytes, not
56         encoded in any kind of way:
57
58                 policy=text:räksmörgås
59
60         Previous versions of this design had a specific tag
61         for UTF-8 text.  However, since the bytes are copied
62         as-is anyway, there's no need for it.  Instead, use
63         the text: tag, like this:
64
65                 policy=text:räksmörgås
66
67   hex   indicates the string is encoded in hex, with colons
68         between each byte (every second hex digit):
69
70                 policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73
71
72         Previous versions of this design had a tag to insert a
73         complete DER blob.  However, the only legal use for
74         this would be to surround the bytes that would go with
75         the hex: tag with what's needed to construct a correct
76         OCTET STRING.  Since hex: does that, the DER tag felt
77         superfluous, and was therefore removed.
78
79   file  indicates that the text of the policy should really be
80         taken from a file.  The string is then really a file
81         name.  This is useful for policies that are large
82         (more than a few of lines) XML documents, for example.
83
84 The 'policy' setting can be split up in multiple lines like this:
85
86   0.policy=This is
87   1.polisy= a multi-
88   2.policy=line policy.
89
90 NOTE: the proxy policy value is the part that determines the rights
91 granted to the process using the proxy certificate.  The value is
92 completely dependent on the application reading and interpretting it!
93
94 Now that you have created an extension section for your proxy
95 certificate, you can now easily create a proxy certificate like this:
96
97   openssl req -new -config openssl.cnf \
98           -out proxy.req -keyout proxy.key
99   openssl x509 -req -CAcreateserial -in proxy.req -days 7 \
100           -out proxy.crt -CA user.crt -CAkey user.key \
101           -extfile openssl.cnf -extensions v3_proxy
102
103 It's just as easy to create a proxy certificate using another proxy
104 certificate as issuer (note that I'm using a different configuration
105 section for it):
106
107   openssl req -new -config openssl.cnf \
108           -out proxy2.req -keyout proxy2.key
109   openssl x509 -req -CAcreateserial -in proxy2.req -days 7 \
110           -out proxy2.crt -CA proxy.crt -CAkey proxy.key \
111           -extfile openssl.cnf -extensions v3_proxy2
112
113
114 3. How to have your application interpret the policy?
115
116 The basic way to interpret proxy policies is to prepare some default
117 rights, then do a check of the proxy certificate against the a chain
118 of proxy certificates, user certificate and CA certificates, and see
119 what rights came out by the end.  Sounds easy, huh?  It almost is.
120
121 The slightly complicated part is how to pass data between your
122 application and the certificate validation procedure.
123
124 You need the following ingredients:
125
126  - a callback routing that will be called for every certificate that's
127    validated.  It will be called several times for each certificates,
128    so you must be attentive to when it's a good time to do the proxy
129    policy interpretation and check, as well as to fill in the defaults
130    when the EE certificate is checked.
131
132  - a structure of data that's shared between your application code and
133    the callback.
134
135  - a wrapper function that sets it all up.
136
137  - an ex_data index function that creates an index into the generic
138    ex_data store that's attached to an X509 validation context.
139
140 This is some cookbook code for you to fill in:
141
142   /* In this example, I will use a view of granted rights as a bit
143      array, one bit for each possible right.  */
144   typedef struct your_rights {
145     unsigned char rights[total_rights / 8];
146   } YOUR_RIGHTS;
147
148   /* The following procedure will create an index for the ex_data
149      store in the X509 validation context the first time it's called.
150      Subsequent calls will return the same index.  */
151   static int get_proxy_auth_ex_data_idx(void)
152   {
153     static volatile int idx = -1;
154     if (idx < 0)
155       {
156         CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
157         if (idx < 0)
158           {
159             idx = X509_STORE_CTX_get_ex_new_index(0,
160                                                   "for verify callback",
161                                                   NULL,NULL,NULL);
162           }
163         CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
164       }
165     return idx;
166   }
167
168   /* Callback to be given to the X509 validation procedure.  */
169   static int verify_callback(int ok, X509_STORE_CTX *ctx)
170   {
171     if (ok == 1) /* It's REALLY important you keep the proxy policy
172                     check within this secion.  It's important to know
173                     that when ok is 1, the certificates are checked
174                     from top to bottom.  You get the CA root first,
175                     followed by the possible chain of intermediate
176                     CAs, followed by the EE certificate, followed by
177                     the possible proxy certificates.  */
178       {
179         X509 *xs = ctx->current_cert;
180
181         if (xs->ex_flags & EXFLAG_PROXY)
182           {
183             YOUR_RIGHTS *rights =
184               (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
185                 get_proxy_auth_ex_data_idx());
186             PROXY_CERT_INFO_EXTENSION *pci =
187               X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL);
188
189             switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage))
190               {
191               case NID_Independent:
192                 /* Do whatever you need to grant explicit rights to
193                    this particular proxy certificate, usually by
194                    pulling them from some database.  If there are none
195                    to be found, clear all rights (making this and any
196                    subsequent proxy certificate void of any rights).
197                 */
198                 memset(rights->rights, 0, sizeof(rights->rights));
199                 break;
200               case NID_id_ppl_inheritAll:
201                 /* This is basically a NOP, we simply let the current
202                    rights stand as they are. */
203                 break;
204               default:
205                 /* This is usually the most complex section of code.
206                    You really do whatever you want as long as you
207                    follow RFC 3820.  In the example we use here, the
208                    simplest thing to do is to build another, temporary
209                    bit array and fill it with the rights granted by
210                    the current proxy certificate, then use it as a
211                    mask on the accumulated rights bit array, and
212                    voilà, you now have a new accumulated rights bit
213                    array.  */
214                 {
215                   int i;
216                   YOUR_RIGHTS tmp_rights;
217                   memset(tmp_rights.rights, 0, sizeof(tmp_rights.rights));
218
219                   /* process_rights() is supposed to be a procedure
220                      that takes a string and it's length, interprets
221                      it and sets the bits in the YOUR_RIGHTS pointed
222                      at by the third argument.  */
223                   process_rights((char *) pci->proxyPolicy->policy->data,
224                                  pci->proxyPolicy->policy->length,
225                                  &tmp_rights);
226
227                   for(i = 0; i < total_rights / 8; i++)
228                     rights->rights[i] &= tmp_rights.rights[i];
229                 }
230                 break;
231               }
232             PROXY_CERT_INFO_EXTENSION_free(pci);
233           }
234         else if (!(xs->ex_flags & EXFLAG_CA))
235           {
236             /* We have a EE certificate, let's use it to set default!
237             */
238             YOUR_RIGHTS *rights =
239               (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
240                 get_proxy_auth_ex_data_idx());
241
242             /* The following procedure finds out what rights the owner
243                of the current certificate has, and sets them in the
244                YOUR_RIGHTS structure pointed at by the second
245                argument.  */
246             set_default_rights(xs, rights);
247           }
248       }
249     return ok;
250   }
251
252   static int my_X509_verify_cert(X509_STORE_CTX *ctx,
253                                  YOUR_RIGHTS *needed_rights)
254   {
255     int i;
256     int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = ctx->verify_cb;
257     YOUR_RIGHTS rights;
258
259     X509_STORE_CTX_set_verify_cb(ctx, verify_callback);
260     X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(), &rights);
261     ok = X509_verify_cert(ctx);
262
263     if (ok == 1)
264       {
265         ok = check_needed_rights(rights, needed_rights);
266       }
267
268     X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb);
269
270     return ok;
271   }
272
273 If you use SSL or TLS, you can easily set up a callback to have the
274 certificates checked properly, using the code above:
275
276   SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, &needed_rights);
277
278
279 -- 
280 Richard Levitte