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 */
oauth_sign_hmac_sha1_raw(const char * m,const size_t ml,const char * k,const size_t kl)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
oauth_sign_hmac_sha1(const char * m,const char * k)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
oauth_body_hash_file(char * filename)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
oauth_body_hash_data(size_t length,const char * data)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
oauth_sign_rsa_sha1(const char * m,const char * k)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
oauth_verify_rsa_sha1(const char * m,const char * c,const char * sig)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
oauth_init_nss()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 */
oauth_strip_pkcs(const char * txt,const char * h,const char * t)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
oauth_sign_hmac_sha1(const char * m,const char * k)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
oauth_sign_hmac_sha1_raw(const char * m,const size_t ml,const char * k,const size_t kl)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
oauth_sign_rsa_sha1(const char * m,const char * k)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
oauth_verify_rsa_sha1(const char * m,const char * c,const char * sig)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
oauth_body_hash_file(char * filename)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
oauth_body_hash_data(size_t length,const char * data)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 #if OPENSSL_VERSION_NUMBER < 0x10100000
366 #define EVP_MD_CTX_new EVP_MD_CTX_create
367 #define EVP_MD_CTX_free EVP_MD_CTX_destroy
368 #endif
369
oauth_sign_hmac_sha1(const char * m,const char * k)370 char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
371 return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
372 }
373
oauth_sign_hmac_sha1_raw(const char * m,const size_t ml,const char * k,const size_t kl)374 char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
375 unsigned char result[EVP_MAX_MD_SIZE];
376 unsigned int resultlen = 0;
377
378 HMAC(EVP_sha1(), k, kl,
379 (unsigned char*) m, ml,
380 result, &resultlen);
381
382 return(oauth_encode_base64(resultlen, result));
383 }
384
385 #include <openssl/evp.h>
386 #include <openssl/x509.h>
387 #include <openssl/x509v3.h>
388 #include <openssl/ssl.h>
389
oauth_sign_rsa_sha1(const char * m,const char * k)390 char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
391 unsigned char *sig = NULL;
392 unsigned char *passphrase = NULL;
393 unsigned int len=0;
394 EVP_MD_CTX *md_ctx;
395
396 EVP_PKEY *pkey;
397 BIO *in;
398 in = BIO_new_mem_buf((unsigned char*) k, strlen(k));
399 pkey = PEM_read_bio_PrivateKey(in, NULL, 0, passphrase); // generate sign
400 BIO_free(in);
401
402 if (pkey == NULL) {
403 //fprintf(stderr, "liboauth/OpenSSL: can not read private key\n");
404 return xstrdup("liboauth/OpenSSL: can not read private key");
405 }
406
407 md_ctx = EVP_MD_CTX_new();
408 if (md_ctx == NULL) {
409 return xstrdup("liboauth/OpenSSL: failed to allocate EVP_MD_CTX");
410 }
411
412
413 len = EVP_PKEY_size(pkey);
414 sig = (unsigned char*)xmalloc((len+1)*sizeof(char));
415
416 EVP_SignInit(md_ctx, EVP_sha1());
417 EVP_SignUpdate(md_ctx, m, strlen(m));
418 if (EVP_SignFinal (md_ctx, sig, &len, pkey)) {
419 char *tmp;
420 sig[len] = '\0';
421 tmp = oauth_encode_base64(len,sig);
422 OPENSSL_free(sig);
423 EVP_PKEY_free(pkey);
424 EVP_MD_CTX_free(md_ctx);
425 return tmp;
426 }
427 EVP_MD_CTX_free(md_ctx);
428 return xstrdup("liboauth/OpenSSL: rsa-sha1 signing failed");
429 }
430
oauth_verify_rsa_sha1(const char * m,const char * c,const char * s)431 int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s) {
432 EVP_MD_CTX *md_ctx;
433 EVP_PKEY *pkey;
434 BIO *in;
435 X509 *cert = NULL;
436 unsigned char *b64d;
437 int slen, err;
438
439 in = BIO_new_mem_buf((unsigned char*)c, strlen(c));
440 cert = PEM_read_bio_X509(in, NULL, 0, NULL);
441 if (cert) {
442 pkey = (EVP_PKEY *) X509_get_pubkey(cert);
443 X509_free(cert);
444 } else {
445 pkey = PEM_read_bio_PUBKEY(in, NULL, 0, NULL);
446 }
447 BIO_free(in);
448 if (pkey == NULL) {
449 //fprintf(stderr, "could not read cert/pubkey.\n");
450 return -2;
451 }
452
453 md_ctx = EVP_MD_CTX_new();
454 if (md_ctx == NULL) {
455 return -2;
456 }
457
458 b64d= (unsigned char*) xmalloc(sizeof(char)*strlen(s));
459 slen = oauth_decode_base64(b64d, s);
460
461 EVP_VerifyInit(md_ctx, EVP_sha1());
462 EVP_VerifyUpdate(md_ctx, m, strlen(m));
463 err = EVP_VerifyFinal(md_ctx, b64d, slen, pkey);
464 EVP_MD_CTX_free(md_ctx);
465 EVP_PKEY_free(pkey);
466 xfree(b64d);
467 return (err);
468 }
469
470
471 /**
472 * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
473 */
oauth_body_hash_file(char * filename)474 char *oauth_body_hash_file(char *filename) {
475 unsigned char fb[BUFSIZ];
476 EVP_MD_CTX *ctx;
477 size_t len=0;
478 unsigned char *md;
479 FILE *F= fopen(filename, "r");
480 if (!F) return NULL;
481
482 ctx = EVP_MD_CTX_new();
483 if (ctx == NULL) {
484 return xstrdup("liboauth/OpenSSL: failed to allocate EVP_MD_CTX");
485 }
486 EVP_DigestInit(ctx,EVP_sha1());
487 while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) {
488 EVP_DigestUpdate(ctx, fb, len);
489 }
490 fclose(F);
491 len=0;
492 md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
493 EVP_DigestFinal(ctx, md,(unsigned int*) &len);
494 EVP_MD_CTX_free(ctx);
495 return oauth_body_hash_encode(len, md);
496 }
497
oauth_body_hash_data(size_t length,const char * data)498 char *oauth_body_hash_data(size_t length, const char *data) {
499 EVP_MD_CTX *ctx;
500 size_t len=0;
501 unsigned char *md;
502 md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
503 ctx = EVP_MD_CTX_new();
504 if (ctx == NULL) {
505 return xstrdup("liboauth/OpenSSL: failed to allocate EVP_MD_CTX");
506 }
507 EVP_DigestInit(ctx,EVP_sha1());
508 EVP_DigestUpdate(ctx, data, length);
509 EVP_DigestFinal(ctx, md,(unsigned int*) &len);
510 EVP_MD_CTX_free(ctx);
511 return oauth_body_hash_encode(len, md);
512 }
513
514 #endif
515
516 // vi: sts=2 sw=2 ts=2
517