aboutsummaryrefslogtreecommitdiff
path: root/openssl/README
blob: a4ca23d2cab9c3a605dd0434e4d9a3306b47475d (plain) (blame)
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
$Id$ -*- Text -*- 

OpenSSL hacked to add support for the RFC 3779 X.509 v3 extensions.

Current status:

- Not (yet) for distribution outside the RIRs.

- Reads and writes RFC 3779 extensions but does not (yet) perform the
  additional validation described in RFC 3779 2.3 & 3.3.

- Not (yet) tested extensively.

Please report any problems to me (sra) or the rescert mailing list.



This is what the current openssl.conf syntax looks like for the RFC
3779 certificate extensions.  Syntax is admittedly wretched, because
it has to work with the existing OpenSSL code.  Within that
restriction, I've attempted to make this look as much as practical
like the existing OpenSSL support for "multi-valued" extensions.  RFC
3779 ASN.1 provided for easy reference.

Notes:

* Ranges are denoted with a hyphen, prefix lengths with a slash.
  I could tag ranges differently from the atomic types, but this
  seemed easier for the user to understand.

* The "@" syntax indicating indirection through a separate section
  is lifted from the stock OpenSSL multi-valued extension support.

* I didn't attempt to guess which addresses are IPv4 and which are
  IPv6 from the syntax, since the opensssl.conf multi-value syntax
  needs tags anyway.

* SAFI support is present but minimal.  If you want a SAFI, you have
  to specify its numeric value.  It would be trivial to add additional
  keywords for specific SAFIs if there were a reason to do so.

* The "sbgp-" names were already present in OpenSSL's table of known
  extension OIDs.  We can talk to the folks at the OpenSSL project
  about changing the names if there's a reason to do so.

### 

# An address extension, all specified on one line

sbgp-ipAddrBlock = critical, IPv4:10.1.1.1/32, IPv4:10.2.0.0-10.3.255.255

# An address extension, all specified on one line, with inheritance

sbgp-ipAddrBlock = critical, IPv4:inherit, IPv6:2002::/16

# An address extension using SAFIs

sbgp-ipAddrBlock = critical, IPv4-SAFI:1:10.1.1.1/32, IPv6-SAFI:1:2002::/16

# Address extension using an indirect section

sbgp-ipAddrBlock = critical, @addr-section

[addr-section]

IPv4.0 = 10.0.0.1
IPv4.1 = 10.0.1.0/24
IPv4.2 = 10.2.0.0 - 10.3.255.255
IPv6.0 = 2002:1::/64
IPv6.1 = 2002:2:: - 2002:8::ffff:ffff:ffff:ffff:ffff

###

# An ASID extension, all specified on one line:

sbgp-autonomousSysNum = critical, AS:44, RDI:33-45

# ASID extension on one line using inheritance

sbgp-autonomousSysNum = critical, AS:55, RDI:inherit

# ASID extension using an indirect section

sbgp-autonomousSysNum = critical, @asid-section

[asid-section]

AS.0  = 44
AS.1  = 55 - 77
RDI.0 = 33



Some notes on OpenSSL internals.

O'Reilly "Network Security with OpenSSL" is a bit dated (four years
old, corresponds roughly to OpenSSL 0.9.7), but still appears to be
the closest thing there is to coherent documentation.  Some updates
and machine readable copies of examples are available at
http://www.opensslbook.com/.  In spite of its age, the book is useful
as it gives a readable overview of bit and pieces of OpenSSL's
internal programming environment which one would otherwise have to
absorb from the code via osmosis.  Chapter 10 is particularly useful,
as are the sections on error handling and abstract I/O (the ERR and
BIO packages, respectively) in chapter 4.

OpenSSL's own doc is very patchy, although fairly extensive in places.
Most of it eventually comes down to "Use the Source, Luke" with
pointers on which bit of source serves as an interesting example.

For x509v3 extentions, the place to start is doc/openssl.txt,
which, oddly, turns out to be mostly about certificate extensions.  It
gives an overview of the mechanisms, in particular of the method
routine interface for certificate extensions.  For something like the
RFC 3779 extensions, it's pretty clear that we need to use a "raw"
extension (which, as far as I can tell, just means that the RFC 3779
stuff is complicated enough that the extension handler has to do a lot
of work to deal with a complex ASN.1 structure that the rest of the
code doesn't know much about).

General note on global symbols in OpenSSL: always look at the header
file for any global symbol you're using.  In fact, it's probably best
to do a global search (m-x tags-search if you're an emacs user) for
all instances of a global symbol before attempting to use it, as there
are a lot of things that one just has to know about how all the global
stuff hangs together.  There are header files full of magic
definitions that one just has to one need to be extended.  There are
magic pre-sorted lists of handlers that one just needs to know about.
Little or none of this is documented.  Use the Source, Luke.

In some cases -portions- of files are automatically generated by Perl
scripts (eg, the per-type stack definitions in safestack.h).  Ouch.
If you see a large block of very repetitive stuff, check for comments
indicating that it's automatically generated.

Oh, and the indentation style is demented.

Header files you definitely need to read if you're going to touch this
stuff:

    crypto/x509v3/x509v3.h
    crypto/x509v3/ext_dat.h
    crypto/stack/safestack.h
    crypto/asn1/asn1t.h
    crypto/asn1/asn1.h
    crypto/objects/objects.h

Automatically generated header files you'll need to skim, then go read
the input files listed in the header comments and perhaps the
generating Perl code:

    crypto/objects/obj_mac.h
    crypto/objects/obj_dat.h

Much of the code shows a heavy Perl influence, presumably dating back
clear to Eric Young.  Some of the internal data structure operators
have names that only make sense to a Perl programmer.  Stacks are
really lists, and may be sorted.  Where code is automatically
generated, it's done by Perl scripts.  The configuration language for
the whole package is a Perl script.  Assembly code is all wrapped up
inside perl scripts in a moderately clever attempt at being able to
write the assembly language only once and use it with various
assemblers with nontrivially different syntax.  Much of the
documentation markup (including manual pages) for the C code is .pod.

I have not yet figured out where to hook in the extra goop that RFC
3779 will need for verification.  Making extensions critical is easy
enough, but the validation stuff in RFC 3779 2.3 and 3.3 needs to go
somewhere.

A lot of the missing documentation is buried in ssleay.txt, which the
other documentation says not to read because it's so old.  But it's
where Eric explains all the basic data structures and expected usage
as of the dawn of time, so most of the stuff that's so old that it's
undocumented is really documented there.

xxx_new() functions set pointers of sub-structures to NULL or allocate
the substructures (one can leak memory if one doesn't know or check
which a particular xxx_new() function has done...), and the xxx_free()
functions clean up complex structures.  So be sure to set unused
pointers to NULL if one has been fiddling.

Make sure that memory leak detection (CRYPTO_MDEBUG) is turned on when
debugging.

"make update" in the top level runs all the magic perl code that
grovels through the code generating error codes, safestacks, etc.
util/mkstack.pl finds DECLARE_STACK_OF() declarations and generates
safestack definitions automatically if you run "make update".  Be
afraid.  Be very very afraid.

My initial test configuration was:

   ./Configure debug -DDEBUG_SAFESTACK

which tried to pull in -lefence (/usr/ports/devel/ElectricFence), so I
installed that.  Sadly, ElectricFence is not kidding when it says it
is very very very slow, but it was the bignum debugging printouts that
were driving me nuts, so I ended up creating my own "debug-sra"
configuration for the options I want.



Random reminders and notes to myself:

- The new stuff in crypto/x509v3/x509v3.h is not organized properly
  yet, it's all lumped in one place rather than being interleved with
  the other supported extensions.  This was to make it easier for me
  to debug, but will proably need to be cleaned up eventually.

- I've seen occasional printouts of what look like empty address
  extensions.  So far the ones I've investigated really have been
  empty; they were created by the APNIC perl code, so I haven't tried
  to figure out whether that was deliberate or a bug.

- It might be possible to get rid of inet_pton(): see ipv4_from_asc()
  and ipv6_from_asc() in v3_utl.c.  Similarly, it might not really be
  necessary to use inet_ntop(), as we're mostly dealing with prefixes
  here and thus can probably get away with a simplified IPv6 printout
  routine that doesn't bother with "::" except at the end of a prefix.

- Right now the library code silently merges duplicates and overlaps.
  It might useful to emit warnings when we do this.  Merging all takes
  place when we're whacking the extension into canonical form, so it
  should be easy to do this; the only hard part is figuring out
  whether the application wants it, and, if so, where the application
  wants it sent.  This probably requires a global variable, either a
  pointer to a BIO stream or a callback (probably the latter as it's
  less likely to cause surprising results running multi-threaded).

- The reference for RDIs in RFC 3779 is incorrect.  I've been told
  that the authoritative definition of RDIs is ISO 10747, available as
  http://www.acm.org/sigs/sigcomm/standards/iso_stds/IDRP/10747.TXT.

- Should we check entire chain or only up to ctx->last_untrusted?  For
  the moment I'm checking the entire chain because that's more likely
  to yield a correct answer, albiet perhaps inefficiently.

- "openssl verify" reports an unknown critical exception error for
  certificatePolicies (RFC 3280 4.2.1.5).

- Right way to handle error reporting from xxx_canonize() functions is
  almost certainly a callback; this would fit fairly well with the
  callback mechanism OpenSSL already uses in X509_validate_cert().

- Do the xxx_canonize() functions may need a mode where they just
  whine and do not attempt to correct the extension?  Or should the
  whining code be separate from the canonizing code even though
  portions of the logic are the same?

- OpenSSL already checks for duplicate extensions: more precisely,
  unless we explicitly tell X509_get_ext_d2i() that we allow multiple
  extensions (by providing the idx parameter), it returns NULL if it
  finds duplicates.  If we really want to check for presence of
  exactly one extension of a particular type, we call this function
  twice with the idx parameter and make sure that the second call
  returns NULL.

- Things we need to check when making sure an extension is
  well-formed:

  - Are all the SEQUENCE OF lists in the right order (check using the
    same comparison function we use with sk_sort())?

  - Are there any overlaps, duplicates, or adjacencies?

  - Are there any ranges that should have been prefixes?

  Should be possible to do all of this with minor reworking of
  existing canonization code, probably moving a lot of the interesting
  stuff out into subroutines.

  Well, but if we want to report -all- the errors in one pass, we may
  need to make temporary copies of the lists (sk_dup()) because that's
  the only sane way to check for overlapping/duplicate/adjacent stuff.

  So for each list, we do sk_dup(), sort, compare sorted with
  unsorted, whine if they differ, walk the sorted list, then free the
  sorted list.  Requires the usual care to avoid memory leaks, but
  nothing extraordinary.

- My path validation stuff is not yet as efficient as it probably
  ought to be.  First off, it starts the check from the trust anchor
  rather than from the target certificate, which is silly (I didn't
  fully understand how X509_verify_cert() worked at the time -- of
  course perhaps I'm kidding myself that I understand it now...).  The
  other thing that it could perhaps do more efficiently would be to
  cache the decoded RFC 3779 extensions in the top-level X509
  structure instead of expanding them every time.  Doesn't much matter
  for a trivial app like the "verify" CLI demo, but if we're going to
  be doing multiple path checks involving the same certificate it'd
  make more sense to expand them once via the same cache mechanism
  that the library already uses for extensions like AKID.  If we did
  this, the code needing modification would be:

  - crypto/x509/x509.h: add rfc3779_addr and rfc3779_asid fields to
    struct x509_st.

  - crypto/asn1/x_x509.c: add initialization and cleanup code to
    x509_cb() (set new fields to NULL for ASN1_OP_NEW_POST, free new
    fields for ASN1_OP_FREE_POST).

  - crypto/x509v3/v3_purp.c: add code to x509v3_cache_extensions() to
    call X509_get_ext_d2i() for our extensions and stash the result in
    the corresponding struct x509_st fields (see the akid handling).

- I need to rewrite the path validation code anyway to allow null
  inheritance, per mailing list discussion.