xref: /freebsd-src/crypto/openssl/doc/man7/proxy-certificates.pod (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
117f01e99SJung-uk Kim=pod
217f01e99SJung-uk Kim
317f01e99SJung-uk Kim=encoding UTF-8
417f01e99SJung-uk Kim
517f01e99SJung-uk Kim=head1 NAME
617f01e99SJung-uk Kim
717f01e99SJung-uk Kimproxy-certificates - Proxy certificates in OpenSSL
817f01e99SJung-uk Kim
917f01e99SJung-uk Kim=head1 DESCRIPTION
1017f01e99SJung-uk Kim
1117f01e99SJung-uk KimProxy certificates are defined in RFC 3820.  They are used to
1217f01e99SJung-uk Kimextend rights to some other entity (a computer process, typically, or
1317f01e99SJung-uk Kimsometimes to the user itself).  This allows the entity to perform
1417f01e99SJung-uk Kimoperations on behalf of the owner of the EE (End Entity) certificate.
1517f01e99SJung-uk Kim
1617f01e99SJung-uk KimThe requirements for a valid proxy certificate are:
1717f01e99SJung-uk Kim
1817f01e99SJung-uk Kim=over 4
1917f01e99SJung-uk Kim
2017f01e99SJung-uk Kim=item *
2117f01e99SJung-uk Kim
2217f01e99SJung-uk KimThey are issued by an End Entity, either a normal EE certificate, or
2317f01e99SJung-uk Kimanother proxy certificate.
2417f01e99SJung-uk Kim
2517f01e99SJung-uk Kim=item *
2617f01e99SJung-uk Kim
2717f01e99SJung-uk KimThey must not have the B<subjectAltName> or B<issuerAltName>
2817f01e99SJung-uk Kimextensions.
2917f01e99SJung-uk Kim
3017f01e99SJung-uk Kim=item *
3117f01e99SJung-uk Kim
3217f01e99SJung-uk KimThey must have the B<proxyCertInfo> extension.
3317f01e99SJung-uk Kim
3417f01e99SJung-uk Kim=item *
3517f01e99SJung-uk Kim
3617f01e99SJung-uk KimThey must have the subject of their issuer, with one B<commonName>
3717f01e99SJung-uk Kimadded.
3817f01e99SJung-uk Kim
3917f01e99SJung-uk Kim=back
4017f01e99SJung-uk Kim
4117f01e99SJung-uk Kim=head2 Enabling proxy certificate verification
4217f01e99SJung-uk Kim
4317f01e99SJung-uk KimOpenSSL expects applications that want to use proxy certificates to be
4417f01e99SJung-uk Kimspecially aware of them, and make that explicit.  This is done by
4517f01e99SJung-uk Kimsetting an X509 verification flag:
4617f01e99SJung-uk Kim
4717f01e99SJung-uk Kim    X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
4817f01e99SJung-uk Kim
4917f01e99SJung-uk Kimor
5017f01e99SJung-uk Kim
5117f01e99SJung-uk Kim    X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_ALLOW_PROXY_CERTS);
5217f01e99SJung-uk Kim
5317f01e99SJung-uk KimSee L</NOTES> for a discussion on this requirement.
5417f01e99SJung-uk Kim
5517f01e99SJung-uk Kim=head2 Creating proxy certificates
5617f01e99SJung-uk Kim
5717f01e99SJung-uk KimCreating proxy certificates can be done using the L<openssl-x509(1)>
5817f01e99SJung-uk Kimcommand, with some extra extensions:
5917f01e99SJung-uk Kim
60*b077aed3SPierre Pronchery    [ proxy ]
6117f01e99SJung-uk Kim    # A proxy certificate MUST NEVER be a CA certificate.
6217f01e99SJung-uk Kim    basicConstraints = CA:FALSE
6317f01e99SJung-uk Kim    # Usual authority key ID
6417f01e99SJung-uk Kim    authorityKeyIdentifier = keyid,issuer:always
6517f01e99SJung-uk Kim    # The extension which marks this certificate as a proxy
6617f01e99SJung-uk Kim    proxyCertInfo = critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB
6717f01e99SJung-uk Kim
6817f01e99SJung-uk KimIt's also possible to specify the proxy extension in a separate section:
6917f01e99SJung-uk Kim
7017f01e99SJung-uk Kim    proxyCertInfo = critical,@proxy_ext
7117f01e99SJung-uk Kim
7217f01e99SJung-uk Kim    [ proxy_ext ]
7317f01e99SJung-uk Kim    language = id-ppl-anyLanguage
7417f01e99SJung-uk Kim    pathlen = 0
7517f01e99SJung-uk Kim    policy = text:BC
7617f01e99SJung-uk Kim
7717f01e99SJung-uk KimThe policy value has a specific syntax, I<syntag>:I<string>, where the
7817f01e99SJung-uk KimI<syntag> determines what will be done with the string.  The following
7917f01e99SJung-uk KimI<syntag>s are recognised:
8017f01e99SJung-uk Kim
8117f01e99SJung-uk Kim=over 4
8217f01e99SJung-uk Kim
8317f01e99SJung-uk Kim=item B<text>
8417f01e99SJung-uk Kim
8517f01e99SJung-uk Kimindicates that the string is a byte sequence, without any encoding:
8617f01e99SJung-uk Kim
8717f01e99SJung-uk Kim    policy=text:räksmörgås
8817f01e99SJung-uk Kim
8917f01e99SJung-uk Kim=item B<hex>
9017f01e99SJung-uk Kim
9117f01e99SJung-uk Kimindicates the string is encoded hexadecimal encoded binary data, with
9217f01e99SJung-uk Kimcolons between each byte (every second hex digit):
9317f01e99SJung-uk Kim
9417f01e99SJung-uk Kim    policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73
9517f01e99SJung-uk Kim
9617f01e99SJung-uk Kim=item B<file>
9717f01e99SJung-uk Kim
9817f01e99SJung-uk Kimindicates that the text of the policy should be taken from a file.
9917f01e99SJung-uk KimThe string is then a filename.  This is useful for policies that are
100*b077aed3SPierre Proncherymore than a few lines, such as XML or other markup.
10117f01e99SJung-uk Kim
10217f01e99SJung-uk Kim=back
10317f01e99SJung-uk Kim
104*b077aed3SPierre ProncheryNote that the proxy policy value is what determines the rights granted
105*b077aed3SPierre Proncheryto the process during the proxy certificate, and it is up to the
10617f01e99SJung-uk Kimapplication to interpret and combine these policies.>
10717f01e99SJung-uk Kim
10817f01e99SJung-uk KimWith a proxy extension, creating a proxy certificate is a matter of
10917f01e99SJung-uk Kimtwo commands:
11017f01e99SJung-uk Kim
11117f01e99SJung-uk Kim    openssl req -new -config proxy.cnf \
11217f01e99SJung-uk Kim        -out proxy.req -keyout proxy.key \
113*b077aed3SPierre Pronchery        -subj "/DC=org/DC=openssl/DC=users/CN=proxy"
11417f01e99SJung-uk Kim
11517f01e99SJung-uk Kim    openssl x509 -req -CAcreateserial -in proxy.req -out proxy.crt \
11617f01e99SJung-uk Kim        -CA user.crt -CAkey user.key -days 7 \
117*b077aed3SPierre Pronchery        -extfile proxy.cnf -extensions proxy
11817f01e99SJung-uk Kim
11917f01e99SJung-uk KimYou can also create a proxy certificate using another proxy
120*b077aed3SPierre Proncherycertificate as issuer. Note that this example uses a different
121*b077aed3SPierre Proncheryconfiguration section for the proxy extensions:
12217f01e99SJung-uk Kim
12317f01e99SJung-uk Kim    openssl req -new -config proxy.cnf \
12417f01e99SJung-uk Kim        -out proxy2.req -keyout proxy2.key \
125*b077aed3SPierre Pronchery        -subj "/DC=org/DC=openssl/DC=users/CN=proxy/CN=proxy 2"
12617f01e99SJung-uk Kim
12717f01e99SJung-uk Kim    openssl x509 -req -CAcreateserial -in proxy2.req -out proxy2.crt \
12817f01e99SJung-uk Kim        -CA proxy.crt -CAkey proxy.key -days 7 \
129*b077aed3SPierre Pronchery        -extfile proxy.cnf -extensions proxy_2
13017f01e99SJung-uk Kim
13117f01e99SJung-uk Kim=head2 Using proxy certs in applications
13217f01e99SJung-uk Kim
13317f01e99SJung-uk KimTo interpret proxy policies, the application would normally start with
13417f01e99SJung-uk Kimsome default rights (perhaps none at all), then compute the resulting
13517f01e99SJung-uk Kimrights by checking the rights against the chain of proxy certificates,
13617f01e99SJung-uk Kimuser certificate and CA certificates.
13717f01e99SJung-uk Kim
13817f01e99SJung-uk KimThe complicated part is figuring out how to pass data between your
13917f01e99SJung-uk Kimapplication and the certificate validation procedure.
14017f01e99SJung-uk Kim
14117f01e99SJung-uk KimThe following ingredients are needed for such processing:
14217f01e99SJung-uk Kim
14317f01e99SJung-uk Kim=over 4
14417f01e99SJung-uk Kim
14517f01e99SJung-uk Kim=item *
14617f01e99SJung-uk Kim
14717f01e99SJung-uk Kima callback function that will be called for every certificate being
14817f01e99SJung-uk Kimvalidated.  The callback is called several times for each certificate,
14917f01e99SJung-uk Kimso you must be careful to do the proxy policy interpretation at the
15017f01e99SJung-uk Kimright time.  You also need to fill in the defaults when the EE
15117f01e99SJung-uk Kimcertificate is checked.
15217f01e99SJung-uk Kim
15317f01e99SJung-uk Kim=item *
15417f01e99SJung-uk Kim
15517f01e99SJung-uk Kima data structure that is shared between your application code and the
15617f01e99SJung-uk Kimcallback.
15717f01e99SJung-uk Kim
15817f01e99SJung-uk Kim=item *
15917f01e99SJung-uk Kim
16017f01e99SJung-uk Kima wrapper function that sets it all up.
16117f01e99SJung-uk Kim
16217f01e99SJung-uk Kim=item *
16317f01e99SJung-uk Kim
16417f01e99SJung-uk Kiman ex_data index function that creates an index into the generic
16517f01e99SJung-uk Kimex_data store that is attached to an X509 validation context.
16617f01e99SJung-uk Kim
16717f01e99SJung-uk Kim=back
16817f01e99SJung-uk Kim
16917f01e99SJung-uk KimThe following skeleton code can be used as a starting point:
17017f01e99SJung-uk Kim
17117f01e99SJung-uk Kim    #include <string.h>
17217f01e99SJung-uk Kim    #include <netdb.h>
17317f01e99SJung-uk Kim    #include <openssl/x509.h>
17417f01e99SJung-uk Kim    #include <openssl/x509v3.h>
17517f01e99SJung-uk Kim
17617f01e99SJung-uk Kim    #define total_rights 25
17717f01e99SJung-uk Kim
17817f01e99SJung-uk Kim    /*
17917f01e99SJung-uk Kim     * In this example, I will use a view of granted rights as a bit
18017f01e99SJung-uk Kim     * array, one bit for each possible right.
18117f01e99SJung-uk Kim     */
18217f01e99SJung-uk Kim    typedef struct your_rights {
18317f01e99SJung-uk Kim        unsigned char rights[(total_rights + 7) / 8];
18417f01e99SJung-uk Kim    } YOUR_RIGHTS;
18517f01e99SJung-uk Kim
18617f01e99SJung-uk Kim    /*
18717f01e99SJung-uk Kim     * The following procedure will create an index for the ex_data
18817f01e99SJung-uk Kim     * store in the X509 validation context the first time it's
18917f01e99SJung-uk Kim     * called.  Subsequent calls will return the same index.
19017f01e99SJung-uk Kim     */
19117f01e99SJung-uk Kim    static int get_proxy_auth_ex_data_idx(X509_STORE_CTX *ctx)
19217f01e99SJung-uk Kim    {
19317f01e99SJung-uk Kim        static volatile int idx = -1;
19417f01e99SJung-uk Kim
19517f01e99SJung-uk Kim        if (idx < 0) {
19617f01e99SJung-uk Kim            X509_STORE_lock(X509_STORE_CTX_get0_store(ctx));
19717f01e99SJung-uk Kim            if (idx < 0) {
19817f01e99SJung-uk Kim                idx = X509_STORE_CTX_get_ex_new_index(0,
19917f01e99SJung-uk Kim                                                      "for verify callback",
20017f01e99SJung-uk Kim                                                      NULL,NULL,NULL);
20117f01e99SJung-uk Kim            }
20217f01e99SJung-uk Kim            X509_STORE_unlock(X509_STORE_CTX_get0_store(ctx));
20317f01e99SJung-uk Kim        }
20417f01e99SJung-uk Kim        return idx;
20517f01e99SJung-uk Kim    }
20617f01e99SJung-uk Kim
20717f01e99SJung-uk Kim    /* Callback to be given to the X509 validation procedure.  */
20817f01e99SJung-uk Kim    static int verify_callback(int ok, X509_STORE_CTX *ctx)
20917f01e99SJung-uk Kim    {
21017f01e99SJung-uk Kim        if (ok == 1) {
21117f01e99SJung-uk Kim            /*
21217f01e99SJung-uk Kim             * It's REALLY important you keep the proxy policy check
21317f01e99SJung-uk Kim             * within this section.  It's important to know that when
21417f01e99SJung-uk Kim             * ok is 1, the certificates are checked from top to
21517f01e99SJung-uk Kim             * bottom.  You get the CA root first, followed by the
21617f01e99SJung-uk Kim             * possible chain of intermediate CAs, followed by the EE
21717f01e99SJung-uk Kim             * certificate, followed by the possible proxy
21817f01e99SJung-uk Kim             * certificates.
21917f01e99SJung-uk Kim             */
22017f01e99SJung-uk Kim            X509 *xs = X509_STORE_CTX_get_current_cert(ctx);
22117f01e99SJung-uk Kim
22217f01e99SJung-uk Kim            if (X509_get_extension_flags(xs) & EXFLAG_PROXY) {
22317f01e99SJung-uk Kim                YOUR_RIGHTS *rights =
22417f01e99SJung-uk Kim                    (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
22517f01e99SJung-uk Kim                        get_proxy_auth_ex_data_idx(ctx));
22617f01e99SJung-uk Kim                PROXY_CERT_INFO_EXTENSION *pci =
22717f01e99SJung-uk Kim                    X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL);
22817f01e99SJung-uk Kim
22917f01e99SJung-uk Kim                switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) {
23017f01e99SJung-uk Kim                case NID_Independent:
23117f01e99SJung-uk Kim                    /*
23217f01e99SJung-uk Kim                     * Do whatever you need to grant explicit rights
23317f01e99SJung-uk Kim                     * to this particular proxy certificate, usually
23417f01e99SJung-uk Kim                     * by pulling them from some database.  If there
23517f01e99SJung-uk Kim                     * are none to be found, clear all rights (making
23617f01e99SJung-uk Kim                     * this and any subsequent proxy certificate void
23717f01e99SJung-uk Kim                     * of any rights).
23817f01e99SJung-uk Kim                     */
23917f01e99SJung-uk Kim                    memset(rights->rights, 0, sizeof(rights->rights));
24017f01e99SJung-uk Kim                    break;
24117f01e99SJung-uk Kim                case NID_id_ppl_inheritAll:
24217f01e99SJung-uk Kim                    /*
24317f01e99SJung-uk Kim                     * This is basically a NOP, we simply let the
24417f01e99SJung-uk Kim                     * current rights stand as they are.
24517f01e99SJung-uk Kim                     */
24617f01e99SJung-uk Kim                    break;
24717f01e99SJung-uk Kim                default:
24817f01e99SJung-uk Kim                    /*
24917f01e99SJung-uk Kim                     * This is usually the most complex section of
25017f01e99SJung-uk Kim                     * code.  You really do whatever you want as long
25117f01e99SJung-uk Kim                     * as you follow RFC 3820.  In the example we use
25217f01e99SJung-uk Kim                     * here, the simplest thing to do is to build
25317f01e99SJung-uk Kim                     * another, temporary bit array and fill it with
25417f01e99SJung-uk Kim                     * the rights granted by the current proxy
25517f01e99SJung-uk Kim                     * certificate, then use it as a mask on the
25617f01e99SJung-uk Kim                     * accumulated rights bit array, and voilà, you
25717f01e99SJung-uk Kim                     * now have a new accumulated rights bit array.
25817f01e99SJung-uk Kim                     */
25917f01e99SJung-uk Kim                    {
26017f01e99SJung-uk Kim                        int i;
26117f01e99SJung-uk Kim                        YOUR_RIGHTS tmp_rights;
26217f01e99SJung-uk Kim                        memset(tmp_rights.rights, 0,
26317f01e99SJung-uk Kim                               sizeof(tmp_rights.rights));
26417f01e99SJung-uk Kim
26517f01e99SJung-uk Kim                        /*
26617f01e99SJung-uk Kim                         * process_rights() is supposed to be a
26717f01e99SJung-uk Kim                         * procedure that takes a string and its
26817f01e99SJung-uk Kim                         * length, interprets it and sets the bits
26917f01e99SJung-uk Kim                         * in the YOUR_RIGHTS pointed at by the
27017f01e99SJung-uk Kim                         * third argument.
27117f01e99SJung-uk Kim                         */
27217f01e99SJung-uk Kim                        process_rights((char *) pci->proxyPolicy->policy->data,
27317f01e99SJung-uk Kim                                       pci->proxyPolicy->policy->length,
27417f01e99SJung-uk Kim                                       &tmp_rights);
27517f01e99SJung-uk Kim
27617f01e99SJung-uk Kim                        for(i = 0; i < total_rights / 8; i++)
27717f01e99SJung-uk Kim                            rights->rights[i] &= tmp_rights.rights[i];
27817f01e99SJung-uk Kim                    }
27917f01e99SJung-uk Kim                    break;
28017f01e99SJung-uk Kim                }
28117f01e99SJung-uk Kim                PROXY_CERT_INFO_EXTENSION_free(pci);
28217f01e99SJung-uk Kim            } else if (!(X509_get_extension_flags(xs) & EXFLAG_CA)) {
28317f01e99SJung-uk Kim                /* We have an EE certificate, let's use it to set default! */
28417f01e99SJung-uk Kim                YOUR_RIGHTS *rights =
28517f01e99SJung-uk Kim                    (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx,
28617f01e99SJung-uk Kim                        get_proxy_auth_ex_data_idx(ctx));
28717f01e99SJung-uk Kim
28817f01e99SJung-uk Kim                /*
28917f01e99SJung-uk Kim                 * The following procedure finds out what rights the
29017f01e99SJung-uk Kim                 * owner of the current certificate has, and sets them
29117f01e99SJung-uk Kim                 * in the YOUR_RIGHTS structure pointed at by the
29217f01e99SJung-uk Kim                 * second argument.
29317f01e99SJung-uk Kim                 */
29417f01e99SJung-uk Kim                set_default_rights(xs, rights);
29517f01e99SJung-uk Kim            }
29617f01e99SJung-uk Kim        }
29717f01e99SJung-uk Kim        return ok;
29817f01e99SJung-uk Kim    }
29917f01e99SJung-uk Kim
30017f01e99SJung-uk Kim    static int my_X509_verify_cert(X509_STORE_CTX *ctx,
30117f01e99SJung-uk Kim                                   YOUR_RIGHTS *needed_rights)
30217f01e99SJung-uk Kim    {
30317f01e99SJung-uk Kim        int ok;
30417f01e99SJung-uk Kim        int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) =
30517f01e99SJung-uk Kim            X509_STORE_CTX_get_verify_cb(ctx);
30617f01e99SJung-uk Kim        YOUR_RIGHTS rights;
30717f01e99SJung-uk Kim
30817f01e99SJung-uk Kim        X509_STORE_CTX_set_verify_cb(ctx, verify_callback);
30917f01e99SJung-uk Kim        X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(ctx),
31017f01e99SJung-uk Kim                                   &rights);
31117f01e99SJung-uk Kim        X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
31217f01e99SJung-uk Kim        ok = X509_verify_cert(ctx);
31317f01e99SJung-uk Kim
31417f01e99SJung-uk Kim        if (ok == 1) {
31517f01e99SJung-uk Kim            ok = check_needed_rights(rights, needed_rights);
31617f01e99SJung-uk Kim        }
31717f01e99SJung-uk Kim
31817f01e99SJung-uk Kim        X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb);
31917f01e99SJung-uk Kim
32017f01e99SJung-uk Kim        return ok;
32117f01e99SJung-uk Kim    }
32217f01e99SJung-uk Kim
32317f01e99SJung-uk KimIf you use SSL or TLS, you can easily set up a callback to have the
32417f01e99SJung-uk Kimcertificates checked properly, using the code above:
32517f01e99SJung-uk Kim
32617f01e99SJung-uk Kim    SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert,
32717f01e99SJung-uk Kim                                     &needed_rights);
32817f01e99SJung-uk Kim
32917f01e99SJung-uk Kim=head1 NOTES
33017f01e99SJung-uk Kim
33117f01e99SJung-uk KimTo this date, it seems that proxy certificates have only been used in
33217f01e99SJung-uk Kimenvironments that are aware of them, and no one seems to have
33317f01e99SJung-uk Kiminvestigated how they can be used or misused outside of such an
33417f01e99SJung-uk Kimenvironment.
33517f01e99SJung-uk Kim
33617f01e99SJung-uk KimFor that reason, OpenSSL requires that applications aware of proxy
33717f01e99SJung-uk Kimcertificates must also make that explicit.
33817f01e99SJung-uk Kim
33917f01e99SJung-uk KimB<subjectAltName> and B<issuerAltName> are forbidden in proxy
34017f01e99SJung-uk Kimcertificates, and this is enforced in OpenSSL.  The subject must be
34117f01e99SJung-uk Kimthe same as the issuer, with one commonName added on.
34217f01e99SJung-uk Kim
34317f01e99SJung-uk Kim=head1 SEE ALSO
34417f01e99SJung-uk Kim
34517f01e99SJung-uk KimL<X509_STORE_CTX_set_flags(3)>,
34617f01e99SJung-uk KimL<X509_STORE_CTX_set_verify_cb(3)>,
34717f01e99SJung-uk KimL<X509_VERIFY_PARAM_set_flags(3)>,
34817f01e99SJung-uk KimL<SSL_CTX_set_cert_verify_callback(3)>,
34917f01e99SJung-uk KimL<openssl-req(1)>, L<openssl-x509(1)>,
35017f01e99SJung-uk KimL<RFC 3820|https://tools.ietf.org/html/rfc3820>
35117f01e99SJung-uk Kim
35217f01e99SJung-uk Kim=head1 COPYRIGHT
35317f01e99SJung-uk Kim
354*b077aed3SPierre ProncheryCopyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
35517f01e99SJung-uk Kim
35617f01e99SJung-uk KimLicensed under the Apache License 2.0 (the "License").  You may not use
35717f01e99SJung-uk Kimthis file except in compliance with the License.  You can obtain a copy
35817f01e99SJung-uk Kimin the file LICENSE in the source distribution or at
35917f01e99SJung-uk KimL<https://www.openssl.org/source/license.html>.
36017f01e99SJung-uk Kim
36117f01e99SJung-uk Kim=cut
362