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