2 HOWTO proxy certificates
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.
12 Proxy certificates are defined in RFC 3820. They are really usual
13 certificates with the mandatory extension proxyCertInfo.
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.
22 See http://www.ietf.org/rfc/rfc3820.txt for more information.
25 2. How to create proxy cerificates
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:
33 # A proxy certificate MUST NEVER be a CA certificate.
34 basicConstraints=CA:FALSE
36 # Usual authority key ID
37 authorityKeyIdentifier=keyid,issuer:always
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
42 It's also possible to give the proxy extension in a separate section:
44 proxyCertInfo=critical,@proxy_ext
47 language=id-ppl-anyLanguage
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:
55 text indicates that the string is simply the bytes, not
56 encoded in any kind of way:
58 policy=text:räksmörgås
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:
65 policy=text:räksmörgås
67 hex indicates the string is encoded in hex, with colons
68 between each byte (every second hex digit):
70 policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73
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.
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.
84 The 'policy' setting can be split up in multiple lines like this:
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!
94 Now that you have created an extension section for your proxy
95 certificate, you can now easily create a proxy certificate like this:
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
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
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
114 3. How to have your application interpret the policy?
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.
121 The slightly complicated part is how to pass data between your
122 application and the certificate validation procedure.
124 You need the following ingredients:
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.
132 - a structure of data that's shared between your application code and
135 - a wrapper function that sets it all up.
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.
140 This is some cookbook code for you to fill in:
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];
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)
153 static volatile int idx = -1;
156 CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
159 idx = X509_STORE_CTX_get_ex_new_index(0,
160 "for verify callback",
163 CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
168 /* Callback to be given to the X509 validation procedure. */
169 static int verify_callback(int ok, X509_STORE_CTX *ctx)
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. */
179 X509 *xs = ctx->current_cert;
181 if (xs->ex_flags & EXFLAG_PROXY)
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);
189 switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage))
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).
198 memset(rights->rights, 0, sizeof(rights->rights));
200 case NID_id_ppl_inheritAll:
201 /* This is basically a NOP, we simply let the current
202 rights stand as they are. */
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
216 YOUR_RIGHTS tmp_rights;
217 memset(tmp_rights.rights, 0, sizeof(tmp_rights.rights));
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,
227 for(i = 0; i < total_rights / 8; i++)
228 rights->rights[i] &= tmp_rights.rights[i];
232 PROXY_CERT_INFO_EXTENSION_free(pci);
234 else if (!(xs->ex_flags & EXFLAG_CA))
236 /* We have a EE certificate, let's use it to set default!
238 YOUR_RIGHTS *rights =
239 (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
240 get_proxy_auth_ex_data_idx());
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
246 set_default_rights(xs, rights);
252 static int my_X509_verify_cert(X509_STORE_CTX *ctx,
253 YOUR_RIGHTS *needed_rights)
256 int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = ctx->verify_cb;
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);
265 ok = check_needed_rights(rights, needed_rights);
268 X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb);
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:
276 SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, &needed_rights);