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. A warning about proxy certificates
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
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.
41 Possible threats are, as far as has been imagined so far:
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
48 For this reason, OpenSSL requires that the use of proxy certificates
49 be explicitely allowed. Currently, this can be done using the
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()):
56 X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
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.
62 There are thoughts to allow proxy certificates with a line in the
63 default openssl.cnf, but that's still in the future.
66 3. How to create proxy cerificates
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:
74 # A proxy certificate MUST NEVER be a CA certificate.
75 basicConstraints=CA:FALSE
77 # Usual authority key ID
78 authorityKeyIdentifier=keyid,issuer:always
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
83 It's also possible to give the proxy extension in a separate section:
85 proxyCertInfo=critical,@proxy_ext
88 language=id-ppl-anyLanguage
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:
96 text indicates that the string is simply the bytes, not
97 encoded in any kind of way:
99 policy=text:räksmörgås
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:
106 policy=text:räksmörgås
108 hex indicates the string is encoded in hex, with colons
109 between each byte (every second hex digit):
111 policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73
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.
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.
125 The 'policy' setting can be split up in multiple lines like this:
129 2.policy=line policy.
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!
135 Now that you have created an extension section for your proxy
136 certificate, you can now easily create a proxy certificate like this:
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
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
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
155 4. How to have your application interpret the policy?
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.
162 The slightly complicated part is how to pass data between your
163 application and the certificate validation procedure.
165 You need the following ingredients:
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.
173 - a structure of data that's shared between your application code and
176 - a wrapper function that sets it all up.
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.
181 This is some cookbook code for you to fill in:
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];
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)
194 static volatile int idx = -1;
197 CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
200 idx = X509_STORE_CTX_get_ex_new_index(0,
201 "for verify callback",
204 CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
209 /* Callback to be given to the X509 validation procedure. */
210 static int verify_callback(int ok, X509_STORE_CTX *ctx)
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. */
220 X509 *xs = ctx->current_cert;
222 if (xs->ex_flags & EXFLAG_PROXY)
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);
230 switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage))
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).
239 memset(rights->rights, 0, sizeof(rights->rights));
241 case NID_id_ppl_inheritAll:
242 /* This is basically a NOP, we simply let the current
243 rights stand as they are. */
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
257 YOUR_RIGHTS tmp_rights;
258 memset(tmp_rights.rights, 0, sizeof(tmp_rights.rights));
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,
268 for(i = 0; i < total_rights / 8; i++)
269 rights->rights[i] &= tmp_rights.rights[i];
273 PROXY_CERT_INFO_EXTENSION_free(pci);
275 else if (!(xs->ex_flags & EXFLAG_CA))
277 /* We have a EE certificate, let's use it to set default!
279 YOUR_RIGHTS *rights =
280 (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
281 get_proxy_auth_ex_data_idx());
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
287 set_default_rights(xs, rights);
293 static int my_X509_verify_cert(X509_STORE_CTX *ctx,
294 YOUR_RIGHTS *needed_rights)
297 int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = ctx->verify_cb;
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);
307 ok = check_needed_rights(rights, needed_rights);
310 X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb);
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:
318 SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, &needed_rights);