Tizen 2.0 Release
[external/libgnutls26.git] / lib / opencdk / seskey.c
1 /* seskey.c - Session key routines
2  * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2007, 2008, 2010 Free
3  * Software Foundation, Inc.
4  *
5  * Author: Timo Schulz
6  *
7  * This file is part of OpenCDK.
8  *
9  * The OpenCDK library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29
30 #include "opencdk.h"
31 #include "main.h"
32 #include "packet.h"
33
34
35 /* We encode the MD in this way:
36  *
37  * 0  1 PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
38  *
39  * PAD consists of FF bytes.
40  */
41 static cdk_error_t
42 do_encode_md (byte ** r_frame, size_t * r_flen, const byte * md, int algo,
43               size_t len, unsigned nbits, const byte * asn, size_t asnlen)
44 {
45   byte *frame = NULL;
46   size_t nframe = (nbits + 7) / 8;
47   ssize_t i;
48   size_t n = 0;
49
50   if (!asn || !md || !r_frame || !r_flen)
51     return CDK_Inv_Value;
52
53   if (len + asnlen + 4 > nframe)
54     return CDK_General_Error;
55
56   frame = cdk_calloc (1, nframe);
57   if (!frame)
58     return CDK_Out_Of_Core;
59   frame[n++] = 0;
60   frame[n++] = 1;
61   i = nframe - len - asnlen - 3;
62   if (i < 0)
63     {
64       cdk_free (frame);
65       return CDK_Inv_Value;
66     }
67   memset (frame + n, 0xFF, i);
68   n += i;
69   frame[n++] = 0;
70   memcpy (frame + n, asn, asnlen);
71   n += asnlen;
72   memcpy (frame + n, md, len);
73   n += len;
74   if (n != nframe)
75     {
76       cdk_free (frame);
77       return CDK_Inv_Value;
78     }
79   *r_frame = frame;
80   *r_flen = n;
81   return 0;
82 }
83
84 static const byte md5_asn[18] = /* Object ID is 1.2.840.113549.2.5 */
85 { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48,
86   0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
87 };
88
89 static const byte sha1_asn[15] =        /* Object ID is 1.3.14.3.2.26 */
90 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
91   0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
92 };
93
94 static const byte sha224_asn[19] =      /* Object ID is 2.16.840.1.101.3.4.2.4 */
95 { 0x30, 0x2D, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
96   0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
97   0x1C
98 };
99
100 static const byte sha256_asn[19] =      /* Object ID is  2.16.840.1.101.3.4.2.1 */
101 { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
102   0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
103   0x00, 0x04, 0x20
104 };
105
106 static const byte sha512_asn[] =        /* Object ID is 2.16.840.1.101.3.4.2.3 */
107 {
108   0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
109   0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
110   0x00, 0x04, 0x40
111 };
112
113 static const byte sha384_asn[] =        /* Object ID is 2.16.840.1.101.3.4.2.2 */
114 {
115   0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
116   0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
117   0x00, 0x04, 0x30
118 };
119
120 static const byte rmd160_asn[15] =      /* Object ID is 1.3.36.3.2.1 */
121 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
122   0x02, 0x01, 0x05, 0x00, 0x04, 0x14
123 };
124
125 static int
126 _gnutls_get_digest_oid (gnutls_digest_algorithm_t algo, const byte ** data)
127 {
128   switch (algo)
129     {
130     case GNUTLS_DIG_MD5:
131       *data = md5_asn;
132       return sizeof (md5_asn);
133     case GNUTLS_DIG_SHA1:
134       *data = sha1_asn;
135       return sizeof (sha1_asn);
136     case GNUTLS_DIG_RMD160:
137       *data = rmd160_asn;
138       return sizeof (rmd160_asn);
139     case GNUTLS_DIG_SHA256:
140       *data = sha256_asn;
141       return sizeof (sha256_asn);
142     case GNUTLS_DIG_SHA384:
143       *data = sha384_asn;
144       return sizeof (sha384_asn);
145     case GNUTLS_DIG_SHA512:
146       *data = sha512_asn;
147       return sizeof (sha512_asn);
148     case GNUTLS_DIG_SHA224:
149       *data = sha224_asn;
150       return sizeof (sha224_asn);
151     default:
152       gnutls_assert ();
153       return GNUTLS_E_INTERNAL_ERROR;
154     }
155 }
156
157
158 /* Encode the given digest into a pkcs#1 compatible format. */
159 cdk_error_t
160 _cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, int pk_algo,
161                           const byte * md, int digest_algo, unsigned nbits)
162 {
163   size_t dlen;
164
165   if (!md || !r_md || !r_mdlen)
166     return CDK_Inv_Value;
167
168   dlen = _gnutls_hash_get_algo_len (digest_algo);
169   if (dlen <= 0)
170     return CDK_Inv_Algo;
171   if (is_DSA (pk_algo))
172     {                           /* DSS does not use a special encoding. */
173       *r_md = cdk_malloc (dlen + 1);
174       if (!*r_md)
175         return CDK_Out_Of_Core;
176       *r_mdlen = dlen;
177       memcpy (*r_md, md, dlen);
178       return 0;
179     }
180   else
181     {
182       const byte *asn;
183       int asnlen;
184       cdk_error_t rc;
185
186       asnlen = _gnutls_get_digest_oid (digest_algo, &asn);
187       if (asnlen < 0)
188         return asnlen;
189
190       rc = do_encode_md (r_md, r_mdlen, md, digest_algo, dlen,
191                          nbits, asn, asnlen);
192       return rc;
193     }
194   return 0;
195 }
196
197
198 /**
199  * cdk_s2k_new:
200  * @ret_s2k: output for the new S2K object
201  * @mode: the S2K mode (simple, salted, iter+salted)
202  * @digest_algo: the hash algorithm
203  * @salt: random salt
204  * 
205  * Create a new S2K object with the given parameter.
206  * The @salt parameter must be always 8 octets.
207  **/
208 cdk_error_t
209 cdk_s2k_new (cdk_s2k_t * ret_s2k, int mode, int digest_algo,
210              const byte * salt)
211 {
212   cdk_s2k_t s2k;
213
214   if (!ret_s2k)
215     return CDK_Inv_Value;
216
217   if (mode != 0x00 && mode != 0x01 && mode != 0x03)
218     return CDK_Inv_Mode;
219
220   if (_gnutls_hash_get_algo_len (digest_algo) <= 0)
221     return CDK_Inv_Algo;
222
223   s2k = cdk_calloc (1, sizeof *s2k);
224   if (!s2k)
225     return CDK_Out_Of_Core;
226   s2k->mode = mode;
227   s2k->hash_algo = digest_algo;
228   if (salt)
229     memcpy (s2k->salt, salt, 8);
230   *ret_s2k = s2k;
231   return 0;
232 }
233
234
235 /**
236  * cdk_s2k_free:
237  * @s2k: the S2K object
238  * 
239  * Release the given S2K object.
240  **/
241 void
242 cdk_s2k_free (cdk_s2k_t s2k)
243 {
244   cdk_free (s2k);
245 }
246
247
248 /* Make a copy of the source s2k into R_DST. */
249 cdk_error_t
250 _cdk_s2k_copy (cdk_s2k_t * r_dst, cdk_s2k_t src)
251 {
252   cdk_s2k_t dst;
253   cdk_error_t err;
254
255   err = cdk_s2k_new (&dst, src->mode, src->hash_algo, src->salt);
256   if (err)
257     return err;
258   dst->count = src->count;
259   *r_dst = dst;
260
261   return 0;
262 }