Make base64 encoding/decoding part of rpmio public API
[platform/upstream/rpm.git] / rpmio / digest_nss.c
1 #include "system.h"
2
3 #include <pthread.h>
4 #include <nss.h>
5 #include <sechash.h>
6 #include <keyhi.h>
7 #include <cryptohi.h>
8
9 #include <rpm/rpmlog.h>
10 #include "rpmio/digest.h"
11 #include "debug.h"
12
13
14 static int _crypto_initialized = 0;
15 static int _new_process = 1;
16
17 /**
18  * MD5/SHA1 digest private data.
19  */
20 struct DIGEST_CTX_s {
21     rpmDigestFlags flags;       /*!< Bit(s) to control digest operation. */
22     HASHContext *hashctx;       /*!< Internal NSS hash context. */
23     int algo;                   /*!< Used hash algorithm */
24 };
25
26 /*
27  * Only flag for re-initialization here, in the common case the child
28  * exec()'s something else shutting down NSS here would be waste of time.
29  */
30 static void at_forkchild(void)
31 {
32     _new_process = 1;
33 }
34
35 int rpmInitCrypto(void)
36 {
37     int rc = 0;
38
39     /* Lazy NSS shutdown for re-initialization after fork() */
40     if (_new_process && _crypto_initialized) {
41         rpmFreeCrypto();
42     }
43
44     /* Initialize NSS if not already done */
45     if (!_crypto_initialized) {
46         if (NSS_NoDB_Init(NULL) != SECSuccess) {
47             rc = -1;
48         } else {
49             _crypto_initialized = 1;
50         }
51     }
52
53     /* Register one post-fork handler per process */
54     if (_new_process) {
55         if (pthread_atfork(NULL, NULL, at_forkchild) != 0) {
56             rpmlog(RPMLOG_WARNING, _("Failed to register fork handler: %m\n"));
57         }
58         _new_process = 0;
59     }
60     return rc;
61 }
62
63 int rpmFreeCrypto(void) 
64 {
65     int rc = 0;
66     if (_crypto_initialized) {
67         rc = (NSS_Shutdown() != SECSuccess);
68         _crypto_initialized = 0;
69     }
70     return rc;
71 }
72
73 DIGEST_CTX rpmDigestDup(DIGEST_CTX octx)
74 {
75     DIGEST_CTX nctx = NULL;
76     if (octx) {
77         HASHContext *hctx = HASH_Clone(octx->hashctx);
78         if (hctx) {
79             nctx = memcpy(xcalloc(1, sizeof(*nctx)), octx, sizeof(*nctx));
80             nctx->hashctx = hctx;
81         }
82     }
83     return nctx;
84 }
85
86 RPM_GNUC_PURE
87 static HASH_HashType getHashType(int hashalgo)
88 {
89     switch (hashalgo) {
90     case PGPHASHALGO_MD5:
91         return HASH_AlgMD5;
92         break;
93     case PGPHASHALGO_MD2:
94         return HASH_AlgMD2;
95         break;
96     case PGPHASHALGO_SHA1:
97         return HASH_AlgSHA1;
98         break;
99     case PGPHASHALGO_SHA256:
100         return HASH_AlgSHA256;
101         break;
102     case PGPHASHALGO_SHA384:
103         return HASH_AlgSHA384;
104         break;
105     case PGPHASHALGO_SHA512:
106         return HASH_AlgSHA512;
107         break;
108     case PGPHASHALGO_RIPEMD160:
109     case PGPHASHALGO_TIGER192:
110     case PGPHASHALGO_HAVAL_5_160:
111     default:
112         return HASH_AlgNULL;
113         break;
114     }
115 }
116
117 size_t rpmDigestLength(int hashalgo)
118 {
119     return HASH_ResultLen(getHashType(hashalgo));
120 }
121
122 DIGEST_CTX rpmDigestInit(int hashalgo, rpmDigestFlags flags)
123 {
124     HASH_HashType type = getHashType(hashalgo);
125     HASHContext *hashctx = NULL;
126     DIGEST_CTX ctx = NULL;
127
128     if (type == HASH_AlgNULL || rpmInitCrypto() < 0)
129         goto exit;
130
131     if ((hashctx = HASH_Create(type)) != NULL) {
132         ctx = xcalloc(1, sizeof(*ctx));
133         ctx->flags = flags;
134         ctx->algo = hashalgo;
135         ctx->hashctx = hashctx;
136         HASH_Begin(ctx->hashctx);
137     }
138     
139 exit:
140     return ctx;
141 }
142
143 int rpmDigestUpdate(DIGEST_CTX ctx, const void * data, size_t len)
144 {
145     size_t partlen;
146     const unsigned char *ptr = data;
147
148     if (ctx == NULL)
149         return -1;
150
151    partlen = ~(unsigned int)0xFF;
152    while (len > 0) {
153         if (len < partlen) {
154                 partlen = len;
155         }
156         HASH_Update(ctx->hashctx, ptr, partlen);
157         ptr += partlen;
158         len -= partlen;
159    }
160    return 0;
161 }
162
163 int rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
164 {
165     unsigned char * digest;
166     unsigned int digestlen;
167
168     if (ctx == NULL)
169         return -1;
170     digestlen = HASH_ResultLenContext(ctx->hashctx);
171     digest = xmalloc(digestlen);
172
173 /* FIX: check rc */
174     HASH_End(ctx->hashctx, digest, (unsigned int *) &digestlen, digestlen);
175
176     /* Return final digest. */
177     if (!asAscii) {
178         if (lenp) *lenp = digestlen;
179         if (datap) {
180             *datap = digest;
181             digest = NULL;
182         }
183     } else {
184         if (lenp) *lenp = (2*digestlen) + 1;
185         if (datap) {
186             const uint8_t * s = (const uint8_t *) digest;
187             *datap = pgpHexStr(s, digestlen);
188         }
189     }
190     if (digest) {
191         memset(digest, 0, digestlen);   /* In case it's sensitive */
192         free(digest);
193     }
194     HASH_Destroy(ctx->hashctx);
195     memset(ctx, 0, sizeof(*ctx));       /* In case it's sensitive */
196     free(ctx);
197     return 0;
198 }
199
200 static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
201                      const uint8_t * p, const uint8_t * pend)
202 {
203     unsigned int mbits = pgpMpiBits(p);
204     unsigned int nbits;
205     size_t nbytes;
206     uint8_t *t = dest;
207     unsigned int ix;
208
209     if ((p + ((mbits+7) >> 3)) > pend)
210         return 1;
211
212     if (mbits > lbits)
213         return 1;
214
215     nbits = (lbits > mbits ? lbits : mbits);
216     nbytes = ((nbits + 7) >> 3);
217     ix = (nbits - mbits) >> 3;
218
219     if (ix > 0)
220         memset(t, '\0', ix);
221     memcpy(t+ix, p+2, nbytes-ix);
222
223     return 0;
224 }
225
226 static SECItem *pgpMpiItem(PRArenaPool *arena, SECItem *item,
227                            const uint8_t *p, const uint8_t *pend)
228 {
229     size_t nbytes = pgpMpiLen(p)-2;
230
231     if (p + nbytes + 2 > pend)
232         return NULL;
233
234     if (item == NULL) {
235         if ((item=SECITEM_AllocItem(arena, item, nbytes)) == NULL)
236             return item;
237     } else {
238         if (arena != NULL)
239             item->data = PORT_ArenaGrow(arena, item->data, item->len, nbytes);
240         else
241             item->data = PORT_Realloc(item->data, nbytes);
242         
243         if (item->data == NULL) {
244             if (arena == NULL)
245                 SECITEM_FreeItem(item, PR_TRUE);
246             return NULL;
247         }
248     }
249
250     memcpy(item->data, p+2, nbytes);
251     item->len = nbytes;
252     return item;
253 }
254
255 static SECKEYPublicKey *pgpNewPublicKey(KeyType type)
256 {
257     PRArenaPool *arena;
258     SECKEYPublicKey *key;
259     
260     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
261     if (arena == NULL)
262         return NULL;
263     
264     key = PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
265     
266     if (key == NULL) {
267         PORT_FreeArena(arena, PR_FALSE);
268         return NULL;
269     }
270     
271     key->keyType = type;
272     key->pkcs11ID = CK_INVALID_HANDLE;
273     key->pkcs11Slot = NULL;
274     key->arena = arena;
275     return key;
276 }
277
278 #ifndef DSA_SUBPRIME_LEN
279 #define DSA_SUBPRIME_LEN 20
280 #endif
281
282 static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
283                            const uint8_t *p, const uint8_t *pend)
284 {
285     SECItem *sig = pgpsig->data;
286     int lbits = DSA_SUBPRIME_LEN * 8;
287     int rc = 1; /* assume failure */
288
289     switch (num) {
290     case 0:
291         sig = pgpsig->data = SECITEM_AllocItem(NULL, NULL, 2*DSA_SUBPRIME_LEN);
292         memset(sig->data, 0, 2 * DSA_SUBPRIME_LEN);
293         rc = pgpMpiSet(lbits, sig->data, p, pend);
294         break;
295     case 1:
296         if (sig && pgpMpiSet(lbits, sig->data+DSA_SUBPRIME_LEN, p, pend) == 0) {
297             SECItem *signew = SECITEM_AllocItem(NULL, NULL, 0);
298             if (signew && DSAU_EncodeDerSig(signew, sig) == SECSuccess) {
299                 SECITEM_FreeItem(sig, PR_TRUE);
300                 pgpsig->data = signew;
301                 rc = 0;
302             }
303         }
304         break;
305     }
306
307     return rc;
308 }
309
310 static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
311                            const uint8_t *p, const uint8_t *pend)
312 {
313     SECItem *mpi = NULL;
314     SECKEYPublicKey *key = pgpkey->data;
315
316     if (key == NULL)
317         key = pgpkey->data = pgpNewPublicKey(dsaKey);
318
319     if (key) {
320         switch (num) {
321         case 0:
322             mpi = pgpMpiItem(key->arena, &key->u.dsa.params.prime, p, pend);
323             break;
324         case 1:
325             mpi = pgpMpiItem(key->arena, &key->u.dsa.params.subPrime, p, pend);
326             break;
327         case 2:
328             mpi = pgpMpiItem(key->arena, &key->u.dsa.params.base, p, pend);
329             break;
330         case 3:
331             mpi = pgpMpiItem(key->arena, &key->u.dsa.publicValue, p, pend);
332             break;
333         }
334     }
335
336     return (mpi == NULL);
337 }
338
339 static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
340                            uint8_t *hash, size_t hashlen, int hash_algo)
341 {
342     SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
343     SECOidTag sigalg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
344     SECStatus rc;
345
346     /* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */ 
347     rc = VFY_VerifyDigest(&digest, pgpkey->data, pgpsig->data, sigalg, NULL);
348
349     return (rc != SECSuccess);
350 }
351
352 static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num,
353                            const uint8_t *p, const uint8_t *pend)
354 {
355     SECItem *sigitem = NULL;
356
357     if (num == 0) {
358        sigitem = pgpMpiItem(NULL, pgpsig->data, p, pend);
359        if (sigitem)
360            pgpsig->data = sigitem;
361     }
362     return (sigitem == NULL);
363 }
364
365 static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
366                            const uint8_t *p, const uint8_t *pend)
367 {
368     SECItem *kitem = NULL;
369     SECKEYPublicKey *key = pgpkey->data;
370
371     if (key == NULL)
372         key = pgpkey->data = pgpNewPublicKey(rsaKey);
373
374     if (key) {
375         switch (num) {
376         case 0:
377             kitem = pgpMpiItem(key->arena, &key->u.rsa.modulus, p, pend);
378             break;
379         case 1:
380             kitem = pgpMpiItem(key->arena, &key->u.rsa.publicExponent, p, pend);
381             break;
382         }
383     }
384
385     return (kitem == NULL);
386 }
387
388 static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
389                            uint8_t *hash, size_t hashlen, int hash_algo)
390 {
391     SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
392     SECItem *sig = pgpsig->data;
393     SECKEYPublicKey *key = pgpkey->data;
394     SECItem *padded = NULL;
395     SECOidTag sigalg;
396     SECStatus rc = SECFailure;
397     size_t siglen, padlen;
398
399     switch (hash_algo) {
400     case PGPHASHALGO_MD5:
401         sigalg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
402         break;
403     case PGPHASHALGO_MD2:
404         sigalg = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
405         break;
406     case PGPHASHALGO_SHA1:
407         sigalg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
408         break;
409     case PGPHASHALGO_SHA256:
410         sigalg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
411         break;
412     case PGPHASHALGO_SHA384:
413          sigalg = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
414         break;
415     case PGPHASHALGO_SHA512:
416         sigalg = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
417         break;
418     default:
419         return 1; /* dont bother with unknown hash types */
420         break;
421     }
422
423     /* Zero-pad signature to expected size if necessary */
424     siglen = SECKEY_SignatureLen(key);
425     padlen = siglen - sig->len;
426     if (padlen) {
427         padded = SECITEM_AllocItem(NULL, NULL, siglen);
428         if (padded == NULL)
429             return 1;
430         memset(padded->data, 0, padlen);
431         memcpy(padded->data + padlen, sig->data, sig->len);
432         sig = padded;
433     }
434
435     /* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */ 
436     rc = VFY_VerifyDigest(&digest, key, sig, sigalg, NULL);
437
438     if (padded)
439         SECITEM_ZfreeItem(padded, PR_TRUE);
440
441     return (rc != SECSuccess);
442 }
443
444 static void pgpFreeSigRSADSA(pgpDigAlg sa)
445 {
446     SECITEM_ZfreeItem(sa->data, PR_TRUE);
447     sa->data = NULL;
448 }
449
450 static void pgpFreeKeyRSADSA(pgpDigAlg ka)
451 {
452     SECKEY_DestroyPublicKey(ka->data);
453     ka->data = NULL;
454 }
455
456 static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num,
457                          const uint8_t *p, const uint8_t *pend)
458 {
459     return 1;
460 }
461
462 static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
463                          uint8_t *hash, size_t hashlen, int hash_algo)
464 {
465     return 1;
466 }
467
468 pgpDigAlg pgpPubkeyNew(int algo)
469 {
470     pgpDigAlg ka = xcalloc(1, sizeof(*ka));;
471
472     switch (algo) {
473     case PGPPUBKEYALGO_RSA:
474         ka->setmpi = pgpSetKeyMpiRSA;
475         ka->free = pgpFreeKeyRSADSA;
476         ka->mpis = 2;
477         break;
478     case PGPPUBKEYALGO_DSA:
479         ka->setmpi = pgpSetKeyMpiDSA;
480         ka->free = pgpFreeKeyRSADSA;
481         ka->mpis = 4;
482         break;
483     default:
484         ka->setmpi = pgpSetMpiNULL;
485         ka->mpis = -1;
486         break;
487     }
488
489     ka->verify = pgpVerifyNULL; /* keys can't be verified */
490
491     return ka;
492 }
493
494 pgpDigAlg pgpSignatureNew(int algo)
495 {
496     pgpDigAlg sa = xcalloc(1, sizeof(*sa));
497
498     switch (algo) {
499     case PGPPUBKEYALGO_RSA:
500         sa->setmpi = pgpSetSigMpiRSA;
501         sa->free = pgpFreeSigRSADSA;
502         sa->verify = pgpVerifySigRSA;
503         sa->mpis = 1;
504         break;
505     case PGPPUBKEYALGO_DSA:
506         sa->setmpi = pgpSetSigMpiDSA;
507         sa->free = pgpFreeSigRSADSA;
508         sa->verify = pgpVerifySigDSA;
509         sa->mpis = 2;
510         break;
511     default:
512         sa->setmpi = pgpSetMpiNULL;
513         sa->verify = pgpVerifyNULL;
514         sa->mpis = -1;
515         break;
516     }
517     return sa;
518 }
519