1 /*
2  * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*****************************************************************************
28  BotanDSAPrivateKey.cpp
29 
30  Botan DSA private key class
31  *****************************************************************************/
32 
33 #include "config.h"
34 #include "log.h"
35 #include "BotanDSAPrivateKey.h"
36 #include "BotanCryptoFactory.h"
37 #include "BotanRNG.h"
38 #include "BotanUtil.h"
39 #include <string.h>
40 #include <botan/pkcs8.h>
41 #include <botan/ber_dec.h>
42 #include <botan/der_enc.h>
43 #include <botan/oids.h>
44 #include <botan/version.h>
45 
46 // Constructors
BotanDSAPrivateKey()47 BotanDSAPrivateKey::BotanDSAPrivateKey()
48 {
49 	dsa = NULL;
50 }
51 
BotanDSAPrivateKey(const Botan::DSA_PrivateKey * inDSA)52 BotanDSAPrivateKey::BotanDSAPrivateKey(const Botan::DSA_PrivateKey* inDSA)
53 {
54 	dsa = NULL;
55 
56 	setFromBotan(inDSA);
57 }
58 
59 // Destructor
~BotanDSAPrivateKey()60 BotanDSAPrivateKey::~BotanDSAPrivateKey()
61 {
62 	delete dsa;
63 }
64 
65 // The type
66 /*static*/ const char* BotanDSAPrivateKey::type = "Botan DSA Private Key";
67 
68 // Set from Botan representation
setFromBotan(const Botan::DSA_PrivateKey * inDSA)69 void BotanDSAPrivateKey::setFromBotan(const Botan::DSA_PrivateKey* inDSA)
70 {
71 	ByteString inP = BotanUtil::bigInt2ByteString(inDSA->group_p());
72 	setP(inP);
73 	ByteString inQ = BotanUtil::bigInt2ByteString(inDSA->group_q());
74 	setQ(inQ);
75 	ByteString inG = BotanUtil::bigInt2ByteString(inDSA->group_g());
76 	setG(inG);
77 	ByteString inX = BotanUtil::bigInt2ByteString(inDSA->get_x());
78 	setX(inX);
79 }
80 
81 // Check if the key is of the given type
isOfType(const char * inType)82 bool BotanDSAPrivateKey::isOfType(const char* inType)
83 {
84 	return !strcmp(type, inType);
85 }
86 
87 // Setters for the DSA private key components
setX(const ByteString & inX)88 void BotanDSAPrivateKey::setX(const ByteString& inX)
89 {
90 	DSAPrivateKey::setX(inX);
91 
92 	if (dsa)
93 	{
94 		delete dsa;
95 		dsa = NULL;
96 	}
97 }
98 
99 
100 // Setters for the DSA domain parameters
setP(const ByteString & inP)101 void BotanDSAPrivateKey::setP(const ByteString& inP)
102 {
103 	DSAPrivateKey::setP(inP);
104 
105 	if (dsa)
106 	{
107 		delete dsa;
108 		dsa = NULL;
109 	}
110 }
111 
setQ(const ByteString & inQ)112 void BotanDSAPrivateKey::setQ(const ByteString& inQ)
113 {
114 	DSAPrivateKey::setQ(inQ);
115 
116 	if (dsa)
117 	{
118 		delete dsa;
119 		dsa = NULL;
120 	}
121 }
122 
setG(const ByteString & inG)123 void BotanDSAPrivateKey::setG(const ByteString& inG)
124 {
125 	DSAPrivateKey::setG(inG);
126 
127 	if (dsa)
128 	{
129 		delete dsa;
130 		dsa = NULL;
131 	}
132 }
133 
134 // Encode into PKCS#8 DER
PKCS8Encode()135 ByteString BotanDSAPrivateKey::PKCS8Encode()
136 {
137 	ByteString der;
138 	createBotanKey();
139 	if (dsa == NULL) return der;
140 	const auto ber = Botan::PKCS8::BER_encode(*dsa);
141 	der.resize(ber.size());
142 	memcpy(&der[0], &ber[0], ber.size());
143 	return der;
144 }
145 
146 // Decode from PKCS#8 BER
PKCS8Decode(const ByteString & ber)147 bool BotanDSAPrivateKey::PKCS8Decode(const ByteString& ber)
148 {
149 	Botan::DataSource_Memory source(ber.const_byte_str(), ber.size());
150 	if (source.end_of_data()) return false;
151 	Botan::secure_vector<uint8_t> keydata;
152 	Botan::AlgorithmIdentifier alg_id;
153 	Botan::DSA_PrivateKey* key = NULL;
154 	try
155 	{
156 
157 		Botan::BER_Decoder(source)
158 		.start_cons(Botan::SEQUENCE)
159 			.decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
160 			.decode(alg_id)
161 			.decode(keydata, Botan::OCTET_STRING)
162 			.discard_remaining()
163 		.end_cons();
164 		if (keydata.empty())
165 			throw Botan::Decoding_Error("PKCS #8 private key decoding failed");
166 		if (Botan::OIDS::lookup(alg_id.oid).compare("DSA"))
167 		{
168 			ERROR_MSG("Decoded private key not DSA");
169 
170 			return false;
171 		}
172 		key = new Botan::DSA_PrivateKey(alg_id, keydata);
173 		if (key == NULL) return false;
174 
175 		setFromBotan(key);
176 
177 		delete key;
178 	}
179 	catch (std::exception& e)
180 	{
181 		ERROR_MSG("Decode failed on %s", e.what());
182 
183 		return false;
184 	}
185 
186 	return true;
187 }
188 
189 // Retrieve the Botan representation of the key
getBotanKey()190 Botan::DSA_PrivateKey* BotanDSAPrivateKey::getBotanKey()
191 {
192 	if (!dsa)
193 	{
194 		createBotanKey();
195 	}
196 
197 	return dsa;
198 }
199 
200 // Create the Botan representation of the key
createBotanKey()201 void BotanDSAPrivateKey::createBotanKey()
202 {
203 	// y is not needed
204 	// Todo: Either q or x is needed. Both is not needed
205 	if (p.size() != 0 &&
206 	    q.size() != 0 &&
207 	    g.size() != 0 &&
208 	    x.size() != 0)
209 	{
210 		if (dsa)
211 		{
212 			delete dsa;
213 			dsa = NULL;
214 		}
215 
216 		try
217 		{
218 			BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
219 			dsa = new Botan::DSA_PrivateKey(*rng->getRNG(),
220 							Botan::DL_Group(BotanUtil::byteString2bigInt(p),
221 							BotanUtil::byteString2bigInt(q),
222 							BotanUtil::byteString2bigInt(g)),
223 							BotanUtil::byteString2bigInt(x));
224 		}
225 		catch (...)
226 		{
227 			ERROR_MSG("Could not create the Botan private key");
228 		}
229 	}
230 }
231