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