uploaded liboauth for tizen_3.0
[platform/upstream/liboauth.git] / src / hash.c
1 /*
2  * hash algorithms used in OAuth 
3  *
4  * Copyright 2007-2012 Robin Gareus <robin@gareus.org>
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  * 
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  * 
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  * 
24  */
25
26 #if HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #if USE_BUILTIN_HASH // built-in / AVR -- TODO: check license of sha1.c
31 #include <stdio.h>
32 #include "oauth.h" // oauth_encode_base64
33 #include "xmalloc.h"
34
35 #include "sha1.c" // TODO: sha1.h ; Makefile.am: add sha1.c
36
37 /* API */
38 char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
39         sha1nfo s;
40         sha1_initHmac(&s, (const uint8_t*) k, kl);
41         sha1_write(&s, m, ml);
42         unsigned char *digest = sha1_resultHmac(&s);
43   return oauth_encode_base64(HASH_LENGTH, digest);
44 }
45
46 char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
47   return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
48 }
49
50 char *oauth_body_hash_file(char *filename) {
51   FILE *F= fopen(filename, "r");
52   if (!F) return NULL;
53
54   size_t len=0;
55   char fb[BUFSIZ];
56         sha1nfo s;
57         sha1_init(&s);
58
59   while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) {
60                 sha1_write(&s, fb, len);
61         }
62   fclose(F);
63
64   unsigned char *dgst = xmalloc(HASH_LENGTH*sizeof(char)); // oauth_body_hash_encode frees the digest..
65   memcpy(dgst, sha1_result(&s), HASH_LENGTH);
66   return oauth_body_hash_encode(HASH_LENGTH, dgst);
67 }
68
69 char *oauth_body_hash_data(size_t length, const char *data) {
70         sha1nfo s;
71         sha1_init(&s);
72         for (;length--;) sha1_writebyte(&s, *data++);
73
74   unsigned char *dgst = xmalloc(HASH_LENGTH*sizeof(char)); // oauth_body_hash_encode frees the digest..
75   memcpy(dgst, sha1_result(&s), HASH_LENGTH);
76   return oauth_body_hash_encode(HASH_LENGTH, dgst);
77 }
78
79 char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
80         /* NOT RSA/PK11 support */
81         return xstrdup("---RSA/PK11-is-not-supported-by-this-version-of-liboauth---");
82 }
83
84 int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) {
85         /* NOT RSA/PK11 support */
86         return -1; // mismatch , error
87 }
88
89 #elif defined (USE_NSS)
90 /* use http://www.mozilla.org/projects/security/pki/nss/ for hash/sign */
91
92 #include <stdio.h>
93 #include <stdlib.h>
94 #include <string.h>
95 #include "xmalloc.h"
96 #include "oauth.h" // oauth base64 encode fn's.
97
98 // NSS includes
99 #include "pk11pub.h"
100 #include "nss.h"
101 #include "base64.h"
102 #include "keyhi.h"
103 #include "cryptohi.h"
104 #include "cert.h"
105
106 #if 1 // work-around compiler-warning
107       // see http://bugzilla.mozilla.org/show_bug.cgi?id=243245#c3
108   extern CERTCertificate *
109   __CERT_DecodeDERCertificate (SECItem *derSignedCert, PRBool copyDER, char *nickname);
110 #endif
111
112 static const char NS_CERT_HEADER[]  = "-----BEGIN CERTIFICATE-----";
113 static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
114 static const char NS_PRIV_HEADER[]  = "-----BEGIN PRIVATE KEY-----";
115 static const char NS_PRIV_TRAILER[] = "-----END PRIVATE KEY-----";
116
117 void oauth_init_nss() {
118   static short nss_initialized = 0;
119   if (!nss_initialized) { NSS_NoDB_Init(NULL); nss_initialized=1;}
120 }
121
122 /**
123  * Removes heading & trailing strings; used only internally.
124  * similar to NSS-source/nss/lib/pkcs7/certread.c
125  *
126  * the returned string (if not NULL) needs to be freed by the caller
127  */
128 char *oauth_strip_pkcs(const char *txt, const char *h, const char *t) {
129   char *start, *end, *rv;
130   size_t len;
131   if ((start=strstr(txt, h))==NULL) return NULL;
132   start+=strlen(h);
133   while (*start=='\r' || *start=='\n') start++;
134   if ((end=strstr(start, t))==NULL) return NULL;
135   end--;
136   while (*end=='\r' || *end=='\n') end--;
137   len = end-start+2;
138   rv = xmalloc(len*sizeof(char));
139   memcpy(rv,start,len);
140   rv[len-1]='\0';
141   return rv;
142 }
143
144 char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
145   return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
146 }
147
148 char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
149   PK11SlotInfo  *slot = NULL;
150   PK11SymKey    *pkey = NULL;
151   PK11Context   *context = NULL;
152   unsigned char  digest[20]; // Is there a way to tell how large the output is?
153   unsigned int   len;
154   SECStatus      s;
155   SECItem        keyItem, noParams;
156   char          *rv=NULL;
157
158   keyItem.type = siBuffer;
159   keyItem.data = (unsigned char*) k;
160   keyItem.len = kl;
161
162   noParams.type = siBuffer;
163   noParams.data = NULL;
164   noParams.len = 0;
165
166   oauth_init_nss();
167
168   slot = PK11_GetInternalKeySlot();
169   if (!slot) goto looser;
170   pkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);
171   if (!pkey)  goto looser;
172   context = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, pkey, &noParams);
173   if (!context) goto looser;
174
175   s = PK11_DigestBegin(context);
176   if (s != SECSuccess) goto looser;
177   s = PK11_DigestOp(context, (unsigned char*) m, ml);
178   if (s != SECSuccess) goto looser;
179   s = PK11_DigestFinal(context, digest, &len, sizeof digest);
180   if (s != SECSuccess) goto looser;
181
182   rv=oauth_encode_base64(len, digest);
183
184 looser:
185   if (context) PK11_DestroyContext(context, PR_TRUE);
186   if (pkey) PK11_FreeSymKey(pkey);
187   if (slot) PK11_FreeSlot(slot);
188   return rv;
189 }
190
191 char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
192   PK11SlotInfo      *slot = NULL;
193   SECKEYPrivateKey  *pkey = NULL;
194   SECItem            signature;
195   SECStatus          s;
196   SECItem            der;
197   char              *rv=NULL;
198
199   char *key = oauth_strip_pkcs(k, NS_PRIV_HEADER, NS_PRIV_TRAILER); 
200   if (!key) return NULL;
201
202   oauth_init_nss();
203
204   slot = PK11_GetInternalKeySlot();
205   if (!slot) goto looser;
206   s = ATOB_ConvertAsciiToItem(&der, key);
207   if (s != SECSuccess) goto looser;
208   s = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, NULL, NULL, PR_FALSE, PR_TRUE, KU_ALL, &pkey, NULL);
209   SECITEM_FreeItem(&der, PR_FALSE);
210   if (s != SECSuccess) goto looser;
211   if (!pkey) goto looser;
212   if (pkey->keyType != rsaKey) goto looser;
213   s = SEC_SignData(&signature, (unsigned char*) m, strlen(m), pkey, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE);
214   if (s != SECSuccess) goto looser;
215
216   rv=oauth_encode_base64(signature.len, signature.data);
217   SECITEM_FreeItem(&signature, PR_FALSE);
218
219 looser:
220   if (pkey) SECKEY_DestroyPrivateKey(pkey);
221   if (slot) PK11_FreeSlot(slot);
222   xfree(key);
223   return rv;
224 }
225
226 int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) {
227   PK11SlotInfo      *slot = NULL;
228   SECKEYPublicKey   *pkey = NULL;
229   CERTCertificate   *cert = NULL;
230   SECItem            signature;
231   SECStatus          s;
232   SECItem            der;
233   int                rv=0;
234
235   char *key = oauth_strip_pkcs(c, NS_CERT_HEADER, NS_CERT_TRAILER); 
236   if (!key) return 0;
237
238   oauth_init_nss();
239
240   s = ATOB_ConvertAsciiToItem(&signature, (char*) sig); // XXX cast (const char*) -> (char*)
241   if (s != SECSuccess) goto looser;
242   slot = PK11_GetInternalKeySlot();
243   if (!slot) goto looser;
244   s = ATOB_ConvertAsciiToItem(&der, key);
245   if (s != SECSuccess) goto looser;
246   cert = __CERT_DecodeDERCertificate(&der, PR_TRUE, NULL);
247   SECITEM_FreeItem(&der, PR_FALSE); 
248   if (!cert) goto looser;
249   pkey = CERT_ExtractPublicKey(cert);
250   if (!pkey) goto looser;
251   if (pkey->keyType != rsaKey) goto looser;
252
253   s = VFY_VerifyData((unsigned char*) m, strlen(m), pkey, &signature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
254   if (s == SECSuccess) rv=1;
255 #if 0
256   else if (PR_GetError()!= SEC_ERROR_BAD_SIGNATURE) rv=-1;
257 #endif
258
259 looser:
260   if (pkey) SECKEY_DestroyPublicKey(pkey);
261   if (slot) PK11_FreeSlot(slot);
262   xfree(key);
263   return rv;
264 }
265
266 char *oauth_body_hash_file(char *filename) {
267   PK11SlotInfo  *slot = NULL;
268   PK11Context   *context = NULL;
269   unsigned char  digest[20]; // Is there a way to tell how large the output is?
270   unsigned int   len;
271   SECStatus      s;
272   char          *rv=NULL;
273   size_t         bl;
274   unsigned char  fb[BUFSIZ];
275
276   FILE *F= fopen(filename, "r");
277   if (!F) return NULL;
278
279   oauth_init_nss();
280
281   slot = PK11_GetInternalKeySlot();
282   if (!slot) goto looser;
283   context = PK11_CreateDigestContext(SEC_OID_SHA1);
284   if (!context) goto looser;
285
286   s = PK11_DigestBegin(context);
287   if (s != SECSuccess) goto looser;
288   while (!feof(F) && (bl=fread(fb,sizeof(char),BUFSIZ, F))>0) {
289     s = PK11_DigestOp(context, (unsigned char*) fb, bl);
290     if (s != SECSuccess) goto looser;
291   }
292   s = PK11_DigestFinal(context, digest, &len, sizeof digest);
293   if (s != SECSuccess) goto looser;
294
295   unsigned char *dgst = xmalloc(len*sizeof(char)); // oauth_body_hash_encode frees the digest..
296   memcpy(dgst, digest, len);
297   rv=oauth_body_hash_encode(len, dgst);
298
299 looser:
300   fclose(F);
301   if (context) PK11_DestroyContext(context, PR_TRUE);
302   if (slot) PK11_FreeSlot(slot);
303   return rv;
304 }
305
306 char *oauth_body_hash_data(size_t length, const char *data) {
307   PK11SlotInfo  *slot = NULL;
308   PK11Context   *context = NULL;
309   unsigned char  digest[20]; // Is there a way to tell how large the output is?
310   unsigned int   len;
311   SECStatus      s;
312   char          *rv=NULL;
313
314   oauth_init_nss();
315
316   slot = PK11_GetInternalKeySlot();
317   if (!slot) goto looser;
318   context = PK11_CreateDigestContext(SEC_OID_SHA1);
319   if (!context) goto looser;
320
321   s = PK11_DigestBegin(context);
322   if (s != SECSuccess) goto looser;
323   s = PK11_DigestOp(context, (unsigned char*) data, length);
324   if (s != SECSuccess) goto looser;
325   s = PK11_DigestFinal(context, digest, &len, sizeof digest);
326   if (s != SECSuccess) goto looser;
327
328   unsigned char *dgst = xmalloc(len*sizeof(char)); // oauth_body_hash_encode frees the digest..
329   memcpy(dgst, digest, len);
330   rv=oauth_body_hash_encode(len, dgst);
331
332 looser:
333   if (context) PK11_DestroyContext(context, PR_TRUE);
334   if (slot) PK11_FreeSlot(slot);
335   return rv;
336 }
337
338 #else 
339 /* use http://www.openssl.org/ for hash/sign */
340
341 #ifdef _GNU_SOURCE
342 /*
343  * In addition, as a special exception, the copyright holders give
344  * permission to link the code of portions of this program with the
345  * OpenSSL library under certain conditions as described in each
346  * individual source file, and distribute linked combinations
347  * including the two.
348  * You must obey the GNU General Public License in all respects
349  * for all of the code used other than OpenSSL.  If you modify
350  * file(s) with this exception, you may extend this exception to your
351  * version of the file(s), but you are not obligated to do so.  If you
352  * do not wish to do so, delete this exception statement from your
353  * version.  If you delete this exception statement from all source
354  * files in the program, then also delete it here.
355  */
356 #endif
357
358 #include <stdio.h>
359 #include <stdlib.h>
360 #include <string.h>
361 #include "xmalloc.h"
362 #include "oauth.h" // base64 encode fn's.
363 #include <openssl/hmac.h>
364
365 char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
366   return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
367 }
368
369 char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
370   unsigned char result[EVP_MAX_MD_SIZE];
371   unsigned int resultlen = 0;
372   
373   HMAC(EVP_sha1(), k, kl, 
374       (unsigned char*) m, ml,
375       result, &resultlen);
376
377   return(oauth_encode_base64(resultlen, result));
378 }
379
380 #include <openssl/evp.h>
381 #include <openssl/x509.h>
382 #include <openssl/x509v3.h>
383 #include <openssl/ssl.h>
384
385 char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
386   unsigned char *sig = NULL;
387   unsigned char *passphrase = NULL;
388   unsigned int len=0;
389   EVP_MD_CTX md_ctx;
390
391   EVP_PKEY *pkey;
392   BIO *in;
393   in = BIO_new_mem_buf((unsigned char*) k, strlen(k));
394   pkey = PEM_read_bio_PrivateKey(in, NULL, 0, passphrase); // generate sign
395   BIO_free(in);
396
397   if (pkey == NULL) {
398   //fprintf(stderr, "liboauth/OpenSSL: can not read private key\n");
399     return xstrdup("liboauth/OpenSSL: can not read private key");
400   }
401
402   len = EVP_PKEY_size(pkey);
403   sig = (unsigned char*)xmalloc((len+1)*sizeof(char));
404
405   EVP_SignInit(&md_ctx, EVP_sha1());
406   EVP_SignUpdate(&md_ctx, m, strlen(m));
407   if (EVP_SignFinal (&md_ctx, sig, &len, pkey)) {
408     char *tmp;
409     sig[len] = '\0';
410     tmp = oauth_encode_base64(len,sig);
411     OPENSSL_free(sig);
412     EVP_PKEY_free(pkey);
413     return tmp;
414   }
415   return xstrdup("liboauth/OpenSSL: rsa-sha1 signing failed");
416 }
417
418 int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s) {
419   EVP_MD_CTX md_ctx;
420   EVP_PKEY *pkey;
421   BIO *in;
422   X509 *cert = NULL;
423   unsigned char *b64d;
424   int slen, err;
425
426   in = BIO_new_mem_buf((unsigned char*)c, strlen(c));
427   cert = PEM_read_bio_X509(in, NULL, 0, NULL);
428   if (cert)  {
429     pkey = (EVP_PKEY *) X509_get_pubkey(cert); 
430     X509_free(cert);
431   } else {
432     pkey = PEM_read_bio_PUBKEY(in, NULL, 0, NULL);
433   }
434   BIO_free(in);
435   if (pkey == NULL) {
436   //fprintf(stderr, "could not read cert/pubkey.\n");
437     return -2;
438   }
439
440   b64d= (unsigned char*) xmalloc(sizeof(char)*strlen(s));
441   slen = oauth_decode_base64(b64d, s);
442
443   EVP_VerifyInit(&md_ctx, EVP_sha1());
444   EVP_VerifyUpdate(&md_ctx, m, strlen(m));
445   err = EVP_VerifyFinal(&md_ctx, b64d, slen, pkey);
446   EVP_MD_CTX_cleanup(&md_ctx);
447   EVP_PKEY_free(pkey);
448   xfree(b64d);
449   return (err);
450 }
451
452
453 /** 
454  * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
455  */
456 char *oauth_body_hash_file(char *filename) {
457   unsigned char fb[BUFSIZ];
458   EVP_MD_CTX ctx;
459   size_t len=0;
460   unsigned char *md;
461   FILE *F= fopen(filename, "r");
462   if (!F) return NULL;
463
464   EVP_MD_CTX_init(&ctx);
465   EVP_DigestInit(&ctx,EVP_sha1());
466   while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) {
467     EVP_DigestUpdate(&ctx, fb, len);
468   }
469   fclose(F);
470   len=0;
471   md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
472   EVP_DigestFinal(&ctx, md,(unsigned int*) &len);
473   EVP_MD_CTX_cleanup(&ctx);
474   return oauth_body_hash_encode(len, md);
475 }
476
477 char *oauth_body_hash_data(size_t length, const char *data) {
478   EVP_MD_CTX ctx;
479   size_t len=0;
480   unsigned char *md;
481   md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
482   EVP_MD_CTX_init(&ctx);
483   EVP_DigestInit(&ctx,EVP_sha1());
484   EVP_DigestUpdate(&ctx, data, length);
485   EVP_DigestFinal(&ctx, md,(unsigned int*) &len);
486   EVP_MD_CTX_cleanup(&ctx);
487   return oauth_body_hash_encode(len, md);
488 }
489
490 #endif
491
492 // vi: sts=2 sw=2 ts=2