1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
|
.. _x509_certificates:
Certificate Handling
=================================
A certificate is a binding between some identifying information
(called a *subject*) and a public key. This binding is asserted
by a signature on the certificate, which is placed there by some
authority (the *issuer*) that at least claims that it knows the
subject named in the certificate really "owns" the private key
corresponding to the public key in the certificate.
The major certificate format in use today is X.509v3, designed by ISO and
further hacked on by dozens (hundreds?) of other organizations.
When working with certificates, the main class to remember is
``X509_Certificate``. You can read an object of this type, but you
can't create one on the fly; a CA object is necessary for making a new
certificate. So for the most part, you only have to worry about
reading them in, verifying the signatures, and getting the bits of
data in them (most commonly the public key, and the information about
the user of that key). An X.509v3 certificate can contain a literally
infinite number of items related to all kinds of things. Botan doesn't
support a lot of them, because nobody uses them and they're an
impossible mess to work with. This section only documents the most
commonly used ones of the ones that are supported; for the rest, read
``x509cert.h`` and ``asn1_obj.h`` (which has the
definitions of various common ASN.1 constructs used in X.509).
So what's in an X.509 certificate?
-----------------------------------
Obviously, you want to be able to get the public key. This is achieved
by calling the member function ``subject_public_key``, which will
return a ``Public_Key``\*. As to what to do with this, read about
``load_key`` in :ref:`serializing_public_keys`. In the general case,
this could be any kind of public key, though 99% of the time it will
be an RSA key. However, Diffie-Hellman, DSA, and ECDSA keys are also
supported, so be careful about how you treat this. It is also a wise
idea to examine the value returned by ``constraints``, to see what
uses the public key is approved for.
The second major piece of information you'll want is the
name/email/etc of the person to whom this certificate is
assigned. Here is where things get a little nasty. X.509v3 has two
(well, mostly just two...) different places where you can stick
information about the user: the *subject* field, and in an extension
called *subjectAlternativeName*. The *subject* field is supposed to
only included the following information: country, organization, an
organizational sub-unit name, and a so-called common name. The common
name is usually the name of the person, or it could be a title
associated with a position of some sort in the organization. It may
also include fields for state/province and locality. What a locality
is, nobody knows, but it's usually given as a city name.
Botan doesn't currently support any of the Unicode variants used in
ASN.1 (UTF-8, UCS-2, and UCS-4), any of which could be used for the
fields in the DN. This could be problematic, particularly in Asia and
other areas where non-ASCII characters are needed for most names. The
UTF-8 and UCS-2 string types *are* accepted (in fact, UTF-8 is
used when encoding much of the time), but if any of the characters
included in the string are not in ISO 8859-1 (ie 0 ... 255), an
exception will get thrown. Currently the ``ASN1_String`` type
holds its data as ISO 8859-1 internally (regardless of local character
set); this would have to be changed to hold UCS-2 or UCS-4 in order to
support Unicode (also, many interfaces in the X.509 code would have to
accept or return a ``std::wstring`` instead of a
``std::string``).
Like the distinguished names, subject alternative names can contain a
lot of things that Botan will flat out ignore (most of which you would
likely never want to use). However, there are three very useful pieces
of information that this extension might hold: an email address
(mailbox@example.com), a DNS name (somehost.example.com), or a URI
(http://www.example.com).
So, how to get the information? Call ``subject_info`` with the name of
the piece of information you want, and it will return a
``std::string`` that is either empty (signifying that the certificate
doesn't have this information), or has the information
requested. There are several names for each possible item, but the
most easily readable ones are: "Name", "Country", "Organization",
"Organizational Unit", "Locality", "State", "RFC822", "URI", and
"DNS". These values are returned as a ``std::string``.
You can also get information about the issuer of the certificate in the same
way, using ``issuer_info``.
X.509v3 Extensions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
X.509v3 specifies a large number of possible extensions. Botan
supports some, but by no means all of them. This section lists which
ones are supported, and notes areas where there may be problems with
the handling.
- Key Usage and Extended Key Usage: No problems known.
- Basic Constraints: No problems known. The default for a v1/v2
certificate is assume it's a CA if and only if the option
"x509/default_to_ca" is set. A v3 certificate is marked as a CA if
(and only if) the basic constraints extension is present and set
for a CA cert.
- Subject Alternative Names: Only the "rfc822Name", "dNSName", and
"uniformResourceIdentifier" fields will be stored; all others are
ignored.
- Issuer Alternative Names: Same restrictions as the Subject
Alternative Names extension. New certificates generated by Botan
never include the issuer alternative name.
- Authority Key Identifier: Only the version using KeyIdentifier is
supported. If the GeneralNames version is used and the extension is
critical, an exception is thrown. If both the KeyIdentifier and
GeneralNames versions are present, then the KeyIdentifier will be
used, and the GeneralNames ignored.
- Subject Key Identifier: No problems known.
Revocation Lists
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It will occasionally happen that a certificate must be revoked before
its expiration date. Examples of this happening include the private
key being compromised, or the user to which it has been assigned
leaving an organization. Certificate revocation lists are an answer to
this problem (though online certificate validation techniques are
starting to become somewhat more popular). Every once in a while the
CA will release a new CRL, listing all certificates that have been
revoked. Also included is various pieces of information like what time
a particular certificate was revoked, and for what reason. In most
systems, it is wise to support some form of certificate revocation,
and CRLs handle this easily.
For most users, processing a CRL is quite easy. All you have to do is call the
constructor, which will take a filename (or a ``DataSource&``). The CRLs
can either be in raw BER/DER, or in PEM format; the constructor will figure out
which format without any extra information. For example::
X509_CRL crl1("crl1.der");
DataSource_Stream in("crl2.pem");
X509_CRL crl2(in);
After that, pass the ``X509_CRL`` object to a ``X509_Store`` object
with
.. cpp:function:: X509_Code X509_Store::add_crl(const X509_CRL& crl)
and all future verifications will take into account the certificates
listed, assuming ``add_crl`` returns ``VERIFIED``. If it doesn't
return ``VERIFIED``, then the return value is an error code signifying
that the CRL could not be processed due to some problem (which could
be something like the issuing certificate could not being found, an
invalid signature, or the CRL having some format problem). For more
about the ``X509_Store`` API, read :ref:`x509_store`.
Reading Certificates
---------------------------------
``X509_Certificate`` has two constructors, each of which takes a source of
data; a filename to read, and a ``DataSource&``.
.. _x509_store:
Storing and Using Certificates
---------------------------------
If you read a certificate, you probably want to verify the signature on
it. However, consider that to do so, we may have to verify the signature on the
certificate that we used to verify the first certificate, and on and on until
we hit the top of the certificate tree somewhere. It would be a might huge pain
to have to handle all of that manually in every application, so there is
something that does it for you: ``X509_Store``.
The basic operations are: put certificates and CRLs into it, search
for certificates, and attempt to verify certificates. That's about
it. In the future, there will be support for online retrieval of
certificates and CRLs (eg with the HTTP cert-store interface
currently under consideration by PKIX).
Adding Certificates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can add new certificates to a certificate store using any of these
functions:
.. cpp:function:: void X509_Store::add_cert(const X509_Certificate& cert, \
bool trusted = false)
.. cpp:function:: void X509_Store::add_cert(DataSource& source)
.. cpp:function:: void X509_Store::add_trusted_certs(DataSource& source)
The versions that take a ``DataSource&`` will add all the certificates
that it can find in that source.
All of them add the cert(s) to the store. The "trusted" certificates
are the ones that you are willing to trust for certification
purposes. For example, say your application is working with
certificates that are owned by employees of some company, and all of
their certificates are signed by the company CA, whose certificate is
in turned signed by a commercial root CA. What you would then do is
include the certificate of the commercial CA with your application,
and read it in as a trusted certificate. From there, you could verify
the company CA's certificate, and then use that to verify the end
user's certificates. Only self-signed certificates may be considered
trusted.
Adding CRLs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. cpp:function:: X509_Code X509_Store::add_crl(const X509_CRL& crl)
This will process the CRL and mark the revoked certificates. This will
also work if a revoked certificate is added to the store sometime
after the CRL is processed. The function can return an error code
(listed later), or will return ``VERIFIED`` if everything completed
successfully.
Storing Certificates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can output a set of certificates by calling ``PEM_encode``, which
will return a ``std::string`` containing each of the certificates in
the store, PEM encoded and concatenated. This simple format can easily
be read by both Botan and other libraries/applications.
Certificate Stores
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An object of type ``Certificate_Store`` is a generalized interface to
an external source for certificates (and CRLs). Examples of such a
store would be one that looked up the certificates in a SQL database,
or by contacting a CGI script running on a HTTP server. There are
currently three mechanisms for looking up a certificate, and one for
retrieving CRLs. By default, most of these mechanisms will return an
empty ``std::vector`` of ``X509_Certificate``. This storage mechanism
is *only* queried when doing certificate validation: it allows you to
distribute only the root key with an application, and let some online
method handle getting all the other certificates that are needed to
validate an end entity certificate. In particular, the search routines
will not attempt to access the external database.
The three certificate lookup methods are ``by_SKID`` (Subject Key
Identifier), ``by_name`` (the CommonName DN entry), and ``by_email``
(stored in either the distinguished name, or in a
subjectAlternativeName extension). The name and email versions take a
``std::string``, while the SKID version takes a ``SecureVector<byte>``
containing the subject key identifier in raw binary. You can choose
not to implement ``by_name`` or ``by_email``, but ``by_SKID`` is
mandatory to implement, and, currently, is the only version that is
used by ``X509_Store``.
Finally, there is a method for finding CRLs, called ``get_crls_for``,
that takes an ``X509_Certificate`` object, and returns a
``std::vector`` of ``X509_CRL``. While normally there will be only one
CRL, the use of the vector makes it easy to return no CRLs (eg, if the
certificate store doesn't support retrieving them), or return multiple
ones (for example, if the certificate store can't determine precisely
which key was used to sign the certificate). Implementing the function
is optional, and by default will return no CRLs. If it is available,
it will be used by ``X509_CRL``.
As for using such a store, you have to tell ``X509_Store`` about
it, by calling the ``X509_Store`` member function
.. cpp:function:: void add_new_certstore(Certificate_Store* new_store)
The store object will be owned by (and deleted by) ``X509_Store``,
so make sure to allocate it with ``new``.
Verifying Certificates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There is a single function in ``X509_Store`` related to verifying a
certificate:
.. .cpp:function:: X509_Code X509_Store::validate_cert(const X509_Certificate& cert, Cert_Usage usage = ANY)
This function will return ``VERIFIED`` if the certificate can
safely be considered valid for the usage(s) described by ``usage``,
and an error code if it is not. Naturally, things are a bit more
complicated than that. The enum ``Cert_Usage`` is defined inside
the ``X509_Store`` class, it (currently) can take on any of the
values ``ANY`` (any usage is OK), ``TLS_SERVER`` (for SSL/TLS
server authentication), ``TLS_CLIENT`` (for SSL/TLS client
authentication), ``CODE_SIGNING``, ``EMAIL_PROTECTION`` (email
encryption, usually this means S/MIME), ``TIME_STAMPING`` (in
theory any time stamp application, usually IETF PKIX's Time Stamp
Protocol), or ``CRL_SIGNING``. Note that Microsoft's code signing
system, certainly the most widely used, uses a completely different
(and mostly undocumented) method for marking certificates for code
signing.
First, how does it know if a certificate is valid? A certificate is
valid if both of the following hold: a) the signature in the
certificate can be verified using the public key in the issuer's
certificate, and b) the issuer's certificate is a valid CA
certificate. Note that this definition is recursive. We get out of
this by "bottoming out" when we reach a certificate that we consider
trusted. In general this will either be a commercial root CA, or an
organization or application specific CA.
There are a few other restrictions (validity periods, key usage
restrictions, etc), but the above summarizes the major points of the
validation algorithm. In theory, Botan implements the certificate path
validation algorithm given in RFC 2459, but in practice it does not
(yet), because we don't support the X.509v3 policy or name constraint
extensions.
Possible values for ``usage`` are ``TLS_SERVER``, ``TLS_CLIENT``,
``CODE_SIGNING``, ``EMAIL_PROTECTION``, ``CRL_SIGNING``, and
``TIME_STAMPING``, and ``ANY``. The default ``ANY`` does not mean
valid for any use, it means "is valid for some usage". This is usually
what you want; requiring that a random certificate support a
particular usage will likely result in a lot of failures, unless your
application is very careful to always issue certificates with the
proper extensions, and you never use certificates generated by other
apps.
Return values for ``validate_cert`` (and ``add_crl``) include:
- VERIFIED: The certificate is valid for the specified use.
- INVALID_USAGE: The certificate cannot be used for the specified use.
- CANNOT_ESTABLISH_TRUST: The root certificate was not marked as
trusted.
- CERT_CHAIN_TOO_LONG: The certificate chain exceeded the length
allowed by a basicConstraints extension.
- SIGNATURE_ERROR: An invalid signature was found
- POLICY_ERROR: Some problem with the certificate policies was found.
- CERT_FORMAT_ERROR: Some format problem was found in a certificate.
- CERT_ISSUER_NOT_FOUND: The issuer of a certificate could not be found.
- CERT_NOT_YET_VALID: The certificate is not yet valid.
- CERT_HAS_EXPIRED: The certificate has expired.
- CERT_IS_REVOKED: The certificate has been revoked.
- CRL_FORMAT_ERROR: Some format problem was found in a CRL.
- CRL_ISSUER_NOT_FOUND: The issuer of a CRL could not be found.
- CRL_NOT_YET_VALID: The CRL is not yet valid.
- CRL_HAS_EXPIRED: The CRL has expired.
- CA_CERT_CANNOT_SIGN: The CA certificate found does not have an
contain a public key that allows signature verification.
- CA_CERT_NOT_FOR_CERT_ISSUER: The CA cert found is not allowed to
issue certificates.
- CA_CERT_NOT_FOR_CRL_ISSUER: The CA cert found is not allowed to
issue CRLs.
- UNKNOWN_X509_ERROR: Some other error occurred.
Certificate Authorities
---------------------------------
Setting up a CA for X.509 certificates is perhaps the easiest thing to
do related to X.509. A CA is represented by the type ``X509_CA``,
which can be found in ``x509_ca.h``. A CA always needs its own
certificate, which can either be a self-signed certificate (see below
on how to create one) or one issued by another CA (see the section on
PKCS #10 requests). Creating a CA object is done by the following
constructor:
.. cpp:function:: X509_CA(const X509_Certificate& cert, const Private_Key& key)
The private key is the private key corresponding to the public key in the
CA's certificate.
Requests for new certificates are supplied to a CA in the form on PKCS
#10 certificate requests (called a ``PKCS10_Request`` object in
Botan). These are decoded in a similar manner to
certificates/CRLs/etc. A request is vetted by humans (who somehow
verify that the name in the request corresponds to the name of the
entity who requested it), and then signed by a CA key, generating a
new certificate:
.. cpp:function:: X509_Certificate sign_request(const PKCS10_Request& req) const
Generating CRLs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As mentioned previously, the ability to process CRLs is highly important in
many PKI systems. In fact, according to strict X.509 rules, you must not
validate any certificate if the appropriate CRLs are not available (though
hardly any systems are that strict). In any case, a CA should have a valid CRL
available at all times.
Of course, you might be wondering what to do if no certificates have
been revoked. Never fear; empty CRLs, which revoke nothing at all, can
be issued. To generate a new, empty CRL, just call
.. cpp:function:: X509_CRL X509_CA::new_crl(u32bit seconds_to_expiration = 0)
This function will return a new, empty CRL. The
``seconds_to_expiration`` parameter is the number of seconds before
the CRL expires. If it is set to the (default) value of zero, then a
reasonable default (currently 7 days) will be used.
On the other hand, you may have issued a CRL before. In that case, you will
want to issue a new CRL that contains all previously revoked
certificates, along with any new ones. This is done by calling
.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& old_crl, \
std::vector<CRL_Entry> new_revoked, size_t seconds_to_expiration = 0)
Where ``X509_CRL`` is the last CRL this CA issued, and
``new_revoked`` is a list of any newly revoked certificates. The
function returns a new ``X509_CRL`` to make available for
clients.
The ``CRL_Entry`` type is a structure that contains, at a minimum, the
serial number of the revoked certificate. As serial numbers are never
repeated, the pairing of an issuer and a serial number (should)
distinctly identify any certificate. In this case, we represent the
serial number as a ``SecureVector<byte>`` called ``serial``. There are
two additional (optional) values, an enumeration called ``CRL_Code``
that specifies the reason for revocation (``reason``), and an object
that represents the time that the certificate became invalid (if this
information is known).
If you wish to remove an old entry from the CRL, insert a new entry for the
same cert, with a ``reason`` code of ``DELETE_CRL_ENTRY``. For example,
if a revoked certificate has expired 'normally', there is no reason to continue
to explicitly revoke it, since clients will reject the cert as expired in any
case.
Self-Signed Certificates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Generating a new self-signed certificate can often be useful, for
example when setting up a new root CA, or for use in email
applications. The library provides a utility function for this:
.. cpp:function:: X509_Certificate create_self_signed_cert( \
const X509_Cert_Options& opts, const Private_Key& key)
Where ``key`` is obviously the private key you wish to use (the public key,
used in the certificate itself, is extracted from the private key), and
``opts`` is an structure that has various bits of information that will be
used in creating the certificate (this structure, and its use, is discussed
below). This function is found in the header ``x509self.h``. There is an
example of using this function in the ``self_sig`` example.
Creating PKCS #10 Requests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Also in ``x509self.h``, there is a function for generating new PKCS #10
certificate requests:
.. cpp:function:: PKCS10_Request create_cert_req( \
const X509_Cert_Options& opts, const Private_Key& key)
This function acts quite similarly to ``create_self_signed_cert``,
except it instead returns a PKCS #10 certificate request. After
creating it, one would typically transmit it to a CA, who signs it and
returns a freshly minted X.509 certificate. There is an example of
using this function in the ``pkcs10`` example.
Certificate Options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What is this ``X509_Cert_Options`` thing we've been passing around?
It's a class representing a bunch of information that will end up
being stored into the certificate. This information comes in 3 major
flavors: information about the subject (CA or end-user), the validity
period of the certificate, and restrictions on the usage of the
certificate.
First and foremost is a number of ``std::string`` members, which
contains various bits of information about the user: ``common_name``,
``serial_number``, ``country``, ``organization``, ``org_unit``,
``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many
of these as possible should be filled it (especially an email
address), though the only required ones are ``common_name`` and
``country``.
There is another value that is only useful when creating a PKCS #10 request,
which is called ``challenge``. This is a challenge password, which you can
later use to request certificate revocation (*if* the CA supports doing
revocations in this manner).
Then there is the validity period; these are set with ``not_before``
and ``not_after``. Both of these functions also take a
``std::string``, which specifies when the certificate should start
being valid, and when it should stop being valid. If you don't set the
starting validity period, it will automatically choose the current
time. If you don't set the ending time, it will choose the starting
time plus a default time period. The arguments to these functions
specify the time in the following format: "2002/11/27 1:50:14". The
time is in 24-hour format, and the date is encoded as
year/month/day. The date must be specified, but you can omit the time
or trailing parts of it, for example "2002/11/27 1:50" or
"2002/11/27".
Lastly, you can set constraints on a key. The one you're mostly likely
to want to use is to create (or request) a CA certificate, which can
be done by calling the member function ``CA_key``. This should only be
used when needed.
Other constraints can be set by calling the member functions
``add_constraints`` and ``add_ex_constraints``. The
first takes a ``Key_Constraints`` value, and replaces any
previously set value. If no value is set, then the certificate key is
marked as being valid for any usage. You can set it to any of the
following (for more than one usage, OR them together):
``DIGITAL_SIGNATURE``, ``NON_REPUDIATION``,
``KEY_ENCIPHERMENT``, ``DATA_ENCIPHERMENT``,
``KEY_AGREEMENT``, ``KEY_CERT_SIGN``, ``CRL_SIGN``,
``ENCIPHER_ONLY``, ``DECIPHER_ONLY``. Many of these have quite
special semantics, so you should either consult the appropriate
standards document (such as RFC 3280), or just not call
``add_constraints``, in which case the appropriate values will
be chosen for you.
The second function, ``add_ex_constraints``, allows you to specify an
OID that has some meaning with regards to restricting the key to
particular usages. You can, if you wish, specify any OID you like, but
there is a set of standard ones that other applications will be able
to understand. These are the ones specified by the PKIX standard, and
are named "PKIX.ServerAuth" (for TLS server authentication),
"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning",
"PKIX.EmailProtection" (most likely for use with S/MIME),
"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and
"PKIX.TimeStamping". You can call "add_ex_constraints" any number of
times - each new OID will be added to the list to include in the
certificate.
|