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
|
* Botan Porting Guide, 1.2.x -> 1.4.x
This is a guide for how to port your code from 1.2.x to 1.4.x. For the most
part, they are compatible, but there are a few cases that might cause
problems. The externally visible changes are much smaller than 1.0->1.2 changes
were. If you run into something that used to work that doesn't now and isn't
mentioned here, let me know so I can either fix it, or document it here.
If you can provide a solid reason for 1.4.x to supply backwards-compatible
behavior with something that's mentioned here, I'll consider it, but no
promises.
* Memory Containers
The memory containers (SecureBuffer, SecureVector) have been changed to
subclass another object, MemoryRegion (a third subclass, MemoryVector, is just
like SecureVector, except it never locks memory - though it will clear it when
freeing). On it's own, this shouldn't cause any problems, but there are some
cases to be aware of.
The ptr() function was renamed begin() to match the STL. This is probably the
change most likely to cause problems.
Various other functions (such as compare) were removed or renamed. The ones
that were removed can be replaced with STL algorithms (for example, compare ->
lexicographical_compare) and the renamed ones were typically renamed to match
the STL.
SecureBuffer can now be resized, so the second template parameter shouldn't be
considered to be the same as the actual size; it is instead the *initial* size
of the buffer. You can get the current size by calling the size() member
function. While it's possible to modify the size of a SecureBuffer now, don't
do it: it's really confusing, and you should just use a SecureVector instead.
Second (optional, but a good idea): convert any functions taking a "const
SecureVector<T>&" to "const MemoryRegion<T>&"; this will let them work with
arbitrary memory types; in particular, it will work with a MemoryVector, which
doesn't lock. In fact, the compiler will convert it for you, but this will slow
things down quite a bit (since copying it requires an allocation and a memcpy),
so it's a good idea to do the change.
* OctetString / SymmetricKey / InitializationVector
This probably wins the 'most likely to cause compile errors' award. There are
two changes:
1) copy() was renamed bits_of()
2) The implicit conversion to byte* was removed. If you were passing it to
another library function as a byte*/u32bit pair, there is probably a version
taking the object directly; use that instead.
If you were using it for something else, do the following: 1) call bits_of()
and use the returned SecureVector<byte> to get the byte* value, and 2) email
me so I can figure out if what you're doing it worth supporting in the
library (obviously strike this last part if what you're doing is so totally
one-off that nobody would ever need it elsewhere).
* BigInt::zero() / BigInt::one()
They were removed. Just use integer constants (0/1) instead; the performance
gain was extremely questionable, and there was lots of special glue to make
sure they worked correctly.
* ASN.1 decoding
If something took an X509_Encoding flag before, it probably doesn't
anymore. Some magical heuristics (BER::maybe_BER and PEM_Code::matches) have
been added which can successfully tell if something is PEM or BER/DER encoded
by looking at the data. The heuristics are not perfect (that's why I'm calling
them heuristics), but they work pretty well, and for the most part you would
have to go quite out of your way to fool them (you will be rewarded for your
hard work with an exception, when the decoding fails).
The places that took it for encoding still do, as the library has no way to
guess which format you want it in.
* General PK
PK_Key::check_params() was renamed check_key() to better reflect what
operations are performed.
* X.509
The first two arguments of X509_CA::update_crl (the list of new entries and the
CRL) have been swapped. Now the CRL is the first argument, and the list of
entires is the second. This just seemed a lot more natural.
CRL_Usage was moved from being a global enumeration to a member of X509_Store,
which makes more sense as that is the only class that uses it. Just replace
CRL_Usage with X509_Store::CRL_Usage, and similarly for any elements of
CRL_Usage (ie, instead of TLS_SERVER, use X509_Store::TLS_SERVER).
* PKCS #8
The PKCS #8 key loading interface has changed significantly in 1.4.0. First,
the versions taking memory objects have been completely removed. While it is,
in fact, quite useful to do this, it's not so useful that it's worth supporting
it in the library (IMO). Just create a DataSource_Memory and pass that to
load_key instead. In fact, here's the code:
PKCS8_PrivateKey* load_key(const SecureVector<byte>& buffer,
const std::string& pass)
{
DataSource_Memory source(buffer);
return PKCS8::load_key(source, pass);
}
See, that was easy. :)
Second, instead of passing a std::string, representing the passphrase, you pass
a User_Interface& object, which a) will not be used if the key isn't encrypted,
and b) will be called as many times as needed until the correct passphrase it
entered (or until the number of tries exceeds the config option
"base/pkcs8_tries", which defaults to 3 (or until the ui object returns
CANCEL_ACTION)).
The base User_Interface class is pretty brain-dead. The constructor takes an
(optional) passphrase, which it spits back out the first time it's called. The
second time it gets called, it will return CANCEL_ACTION. This behavior is for
compatibility with the old std::string interface (the functions still exist as
forwarding functions, which just create the base UI object and pass it to the
real decoding functions).
Updating your code to use the new PKCS #8 functions could make things much
nicer in your interface (for example, popping up a dialog box that asks for the
passphrase, but only if the key really is encrypted). There is a GTK+ example
that shows how to do this, check the web page.
* Public/Private Keys
This is a pretty big change. Almost all of the PK objects used to have a
constructor taking a DataSource&, from which it would read the key. However,
this was a poor design, because if you guess incorrectly as to what kind of key
was in use, bad stuff would happen. So basically it was impossible to use
safely. In addition, it was rather complex to support.
Use {X509,PKCS8}::load_key and dynamic_cast<> instead. It's a bit more code,
but it's worth it for the flexibility and better error handling. If you really
want something like the constructors, you can look at the try_load functions in
1.2.x's pkcs8.cpp and x509_key.cpp to see how they did it (you won't get the
same exact effect, since you can't add a constructor, but you can do something
that looks fairly similar).
|