/* --- Object methods */ static JSBool rpmdc_Init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { void * ptr = JS_GetInstancePrivate(cx, obj, &rpmdcClass, NULL); rpmdc dc = ptr; JSBool ok = JS_FALSE; unsigned int _dalgo = PGPHASHALGO_NONE; unsigned int _flags = RPMDIGEST_NONE; _METHOD_DEBUG_ENTRY(_debug); if (!(ok = JS_ConvertArguments(cx, argc, argv, "/uu", &_dalgo, &_flags))) goto exit; if (dc) { if (_dalgo == PGPHASHALGO_NONE) _dalgo = rpmDigestAlgo(dc); (void) rpmDigestFinal(dc, NULL, NULL, 0); (void) JS_SetPrivate(cx, obj, (void *)NULL); } if (_dalgo == PGPHASHALGO_NONE) _dalgo = _dalgo_default; dc = rpmDigestInit(_dalgo, _flags); (void) JS_SetPrivate(cx, obj, (void *)dc); *rval = JSVAL_TRUE; ok = JS_TRUE; exit: return ok; }
static void *nullDigest(int algo, int ascii) { void *d = NULL; DIGEST_CTX ctx = rpmDigestInit(algo, 0); rpmDigestFinal(ctx, &d, NULL, ascii); return d; }
static int hBlobDigest(Header h, pgpDig dig, pgpHashAlgo hash_algo, DIGEST_CTX * ctxp) { HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); rpmop op = NULL; unsigned char * hmagic = NULL; size_t nmagic = 0; int xx; he->tag = RPMTAG_HEADERIMMUTABLE; xx = headerGet(h, he, 0); if (!xx) goto exit; (void) headerGetMagic(NULL, &hmagic, &nmagic); op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ (void) rpmswEnter(op, 0); *ctxp = rpmDigestInit(hash_algo, RPMDIGEST_NONE); if (hmagic && nmagic > 0) { (void) rpmDigestUpdate(*ctxp, hmagic, nmagic); dig->nbytes += nmagic; } (void) rpmDigestUpdate(*ctxp, he->p.ptr, he->c); dig->nbytes += he->c; (void) rpmswExit(op, dig->nbytes); op->count--; /* XXX one too many */ exit: he->p.ptr = _free(he->p.ptr); return xx; }
static int makeHDRDigest(Header sigh, const char * file, rpmTagVal sigTag) { Header h = NULL; FD_t fd = NULL; char * SHA1 = NULL; int ret = -1; /* assume failure. */ switch (sigTag) { case RPMSIGTAG_SHA1: fd = Fopen(file, "r.fdio"); if (fd == NULL || Ferror(fd)) goto exit; h = headerRead(fd, HEADER_MAGIC_YES); if (h == NULL) goto exit; if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { DIGEST_CTX ctx; struct rpmtd_s utd; if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT) || utd.data == NULL) { rpmlog(RPMLOG_ERR, _("Immutable header region could not be read. " "Corrupted package?\n")); goto exit; } ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); (void) rpmDigestUpdate(ctx, utd.data, utd.count); (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1); rpmtdFreeData(&utd); } else { rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n")); goto exit; } if (SHA1 == NULL) goto exit; if (!sighdrPut(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1)) goto exit; ret = 0; break; default: break; } exit: free(SHA1); headerFree(h); if (fd != NULL) (void) Fclose(fd); return ret; }
/* --- Object ctors/dtors */ static rpmdc rpmdc_init(JSContext *cx, JSObject *obj, unsigned int _dalgo, unsigned int _flags) { rpmdc dc = (_dalgo > 0 ? rpmDigestInit(_dalgo, _flags) : NULL); if (_debug) fprintf(stderr, "==> %s(%p,%p,%u,%u) dc %p\n", __FUNCTION__, cx, obj, _dalgo, _flags, dc); if (!JS_SetPrivate(cx, obj, (void *)dc)) { /* XXX error msg */ return NULL; } return dc; }
int rpmDigestBundleAdd(rpmDigestBundle bundle, int algo, rpmDigestFlags flags) { DIGEST_CTX ctx = NULL; if (bundle && algo > 0 && algo < DIGESTS_MAX) { if (bundle->digests[algo] == NULL) { ctx = rpmDigestInit(algo, flags); if (ctx) { bundle->digests[algo] = ctx; if (algo < bundle->index_min) { bundle->index_min = algo; } if (algo > bundle->index_max) { bundle->index_max = algo; } } } } return (ctx != NULL); }
static void test_gridfile( gridfs *gfs, char *data_before, int64_t length, char *filename, char *content_type ) { gridfile gfile[1]; FILE *stream; #ifdef DYING mongo_md5_state_t pms[1]; mongo_md5_byte_t digest[16]; #endif char hex_digest[33]; int64_t i = length; int n; char *data_after = (char*)bson_malloc( LARGE ); int truncBytes; char* lowerName; ASSERT(gridfs_find_filename( gfs, filename, gfile ) == MONGO_OK); ASSERT( gridfile_exists( gfile ) ); stream = fopen( "output", "w+" ); gridfile_write_file( gfile, stream ); fseek( stream, 0, SEEK_SET ); ASSERT( fread( data_after, (size_t)length, sizeof( char ), stream ) ); fclose( stream ); ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); gridfile_read_buffer( gfile, data_after, length ); ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); lowerName = (char*) bson_malloc( (int)strlen( filename ) + 1); strcpy( lowerName, filename ); _strlwr( lowerName ); ASSERT( strcmp( gridfile_get_filename( gfile ), lowerName ) == 0 ); bson_free( lowerName ); ASSERT( gridfile_get_contentlength( gfile ) == (size_t)length ); ASSERT( gridfile_get_chunksize( gfile ) == DEFAULT_CHUNK_SIZE ); ASSERT( strcmp( gridfile_get_contenttype( gfile ), content_type ) == 0 ) ; ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); if( !( gfile->flags & GRIDFILE_COMPRESS ) ) { #ifdef DYING mongo_md5_init( pms ); n = 0; while( i > INT_MAX ) { mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), INT_MAX ); i -= INT_MAX; n += 1; } if( i > 0 ) mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), (int)i ); mongo_md5_finish( pms, digest ); digest2hex( digest, hex_digest ); #else { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE); const char * _digest = NULL; int xx; while( i > INT_MAX ) { xx = rpmDigestUpdate(ctx, (char *)data_before + (n*INT_MAX), INT_MAX); i -= INT_MAX; n += 1; } xx = rpmDigestFinal(ctx, &_digest, NULL, 1); strncpy(hex_digest, _digest, 32+1); hex_digest[32] = '\0'; _digest = _free(_digest); } #endif ASSERT( strcmp( gridfile_get_md5( gfile ), hex_digest ) == 0 ); } truncBytes = (int) (length > DEFAULT_CHUNK_SIZE * 4 ? length - DEFAULT_CHUNK_SIZE * 2 - 13 : 23); gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT); ASSERT( gridfile_truncate(gfile, (size_t)(length - truncBytes)) == (size_t)(length - truncBytes)); gridfile_writer_done( gfile ); gridfile_seek(gfile, 0); ASSERT( gridfile_get_contentlength( gfile ) == (size_t)(length - truncBytes) ); ASSERT( gridfile_read_buffer( gfile, data_after, length ) == (size_t)(length - truncBytes)); ASSERT( memcmp( data_before, data_after, (size_t)(length - truncBytes) ) == 0 ); gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT); gridfile_truncate(gfile, 0); gridfile_writer_done( gfile ); ASSERT( gridfile_get_contentlength( gfile ) == 0 ); ASSERT( gridfile_read_buffer( gfile, data_after, length ) == 0 ); gridfile_destroy( gfile ); ASSERT( gridfs_remove_filename( gfs, filename ) == MONGO_OK ); free( data_after ); gridfs_test_unlink( "output" ); }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, Header * hdrp, unsigned int *keyidp, char **msg) { pgpDigParams sig = NULL; Header sigh = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; struct sigtInfo_s sinfo; Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; if (hdrp) *hdrp = NULL; rpmtdReset(&sigtd); if ((rc = rpmLeadRead(fd, &leadtype, msg)) != RPMRC_OK) { /* Avoid message spew on manifests */ if (rc == RPMRC_NOTFOUND) { *msg = _free(*msg); } goto exit; } /* Read the signature header. */ rc = rpmReadSignature(fd, &sigh, msg); if (rc != RPMRC_OK) { goto exit; } #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective means of verification available, prefer * signatures over digests. Legacy header+payload entries are not used. * DSA will be preferred over RSA if both exist because tested first. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; rc = rpmpkgReadHeader(fd, &h, msg); if (rc != RPMRC_OK || h == NULL) { goto exit; } /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } /* Free up any previous "ok" message before signature/digest check */ *msg = _free(*msg); /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } if (rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, msg) == RPMRC_OK) { struct rpmtd_s utd; DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE); if (headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) { rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, msg); rpmDigestFinal(ctx, NULL, NULL, 0); } else { rc = RPMRC_FAIL; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having immutable region * equals a truly ancient package, do full retrofit. OTOH newer * packages might have been built with --nodirtokens, test and handle * the non-compressed filelist case separately. */ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) headerConvert(h, HEADERCONV_RETROFIT_V3); else if (headerIsEntry(h, RPMTAG_OLDFILENAMES)) headerConvert(h, HEADERCONV_COMPRESSFILELIST); /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); if (keyidp) *keyidp = getKeyid(sig); } rpmtdFreeData(&sigtd); h = headerFree(h); pgpDigParamsFree(sig); sigh = headerFree(sigh); return rc; }
/* * Argument monster to verify header-only signature/digest if there is * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check. */ static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags, hdrblob blob, char **buf) { rpmRC rc = RPMRC_FAIL; pgpDigParams sig = NULL; struct rpmtd_s sigtd; struct entryInfo_s einfo; struct sigtInfo_s sinfo; rpmtdReset(&sigtd); memset(&einfo, 0, sizeof(einfo)); /* Find a header-only digest/signature tag. */ for (int i = blob->ril; i < blob->il; i++) { ei2h(blob->pe+i, &einfo); switch (einfo.tag) { case RPMTAG_SHA1HEADER: if (vsflags & RPMVSF_NOSHA1HEADER) break; if (sigtd.tag == 0) ei2td(&einfo, blob->dataStart, 0, &sigtd); break; case RPMTAG_RSAHEADER: if (vsflags & RPMVSF_NORSAHEADER) break; ei2td(&einfo, blob->dataStart, einfo.count, &sigtd); break; case RPMTAG_DSAHEADER: if (vsflags & RPMVSF_NODSAHEADER) break; ei2td(&einfo, blob->dataStart, einfo.count, &sigtd); break; default: break; } } /* No header-only digest/signature found, get outta here */ if (sigtd.tag == 0) { rc = RPMRC_NOTFOUND; goto exit; } if (rpmSigInfoParse(&sigtd, "header", &sinfo, &sig, buf)) goto exit; if (sinfo.hashalgo) { DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE); int32_t ildl[2] = { htonl(blob->ril), htonl(blob->rdl) }; rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, ildl, sizeof(ildl)); rpmDigestUpdate(ctx, blob->pe, (blob->ril * sizeof(*blob->pe))); rpmDigestUpdate(ctx, blob->dataStart, blob->rdl); rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf); rpmDigestFinal(ctx, NULL, NULL, 0); } exit: rpmtdFreeData(&sigtd); pgpDigParamsFree(sig); return rc; }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, const char * fn, Header * hdrp) { pgpDig dig = NULL; char buf[8*BUFSIZ]; ssize_t count; rpmlead l = NULL; Header sigh = NULL; rpmSigTag sigtag; struct rpmtd_s sigtd; Header h = NULL; char * msg; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; DIGEST_CTX ctx = NULL; if (hdrp) *hdrp = NULL; rpmtdReset(&sigtd); l = rpmLeadNew(); if ((rc = rpmLeadRead(fd, l)) == RPMRC_OK) { const char * err = NULL; if ((rc = rpmLeadCheck(l, &err)) == RPMRC_FAIL) { rpmlog(RPMLOG_ERR, "%s: %s\n", fn, err); } leadtype = rpmLeadType(l); } l = rpmLeadFree(l); if (rc != RPMRC_OK) goto exit; /* Read the signature header. */ msg = NULL; rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; break; case RPMRC_OK: if (sigh == NULL) { rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); rc = RPMRC_FAIL; goto exit; } break; } msg = _free(msg); #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective available signature. * Prefer signatures over digests, then header-only over header+payload. * DSA will be preferred over RSA if both exist because tested first. * Note that NEEDPAYLOAD prevents header+payload signatures and digests. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) { sigtag = RPMSIGTAG_GPG; fdInitDigest(fd, PGPHASHALGO_SHA1, 0); } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) { sigtag = RPMSIGTAG_PGP; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) { sigtag = RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg); if (rc != RPMRC_OK || h == NULL) { rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; } msg = _free(msg); /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } dig = pgpNewDig(); if (dig == NULL) { rc = RPMRC_FAIL; goto exit; } /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } switch (sigtag) { case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) { goto exit; } /* fallthrough */ case RPMSIGTAG_SHA1: { struct rpmtd_s utd; pgpHashAlgo hashalgo = (sigtag == RPMSIGTAG_SHA1) ? PGPHASHALGO_SHA1 : dig->signature.hash_algo; if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) break; ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); (void) rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } break; case RPMSIGTAG_GPG: case RPMSIGTAG_PGP5: /* XXX legacy */ case RPMSIGTAG_PGP: if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) { goto exit; } /* fallthrough */ case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {} if (count < 0) { rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); rc = RPMRC_FAIL; goto exit; } ctx = rpmDigestBundleDupCtx(fdGetBundle(fd), (sigtag == RPMSIGTAG_MD5) ? PGPHASHALGO_MD5 : dig->signature.hash_algo); break; default: break; } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &msg); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (stashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s", fn, msg); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg); break; default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s", fn, msg); break; } free(msg); exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having "new" style compressed * filenames is close enough estimate for legacy indication... */ if (!headerIsEntry(h, RPMTAG_DIRNAMES)) { headerConvert(h, HEADERCONV_RETROFIT_V3); } /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } rpmtdFreeData(&sigtd); rpmDigestFinal(ctx, NULL, NULL, 0); h = headerFree(h); pgpFreeDig(dig); sigh = rpmFreeSignature(sigh); return rc; }
static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags, const void * uh, size_t uc, char ** msg) { pgpDig dig = NULL; char *buf = NULL; int32_t * ei = (int32_t *) uh; int32_t il = ntohl(ei[0]); int32_t dl = ntohl(ei[1]); entryInfo pe = (entryInfo) &ei[2]; int32_t ildl[2]; int32_t pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl; unsigned char * dataStart = (unsigned char *) (pe + il); struct indexEntry_s entry; struct entryInfo_s info; unsigned const char * b; size_t siglen = 0; size_t blen; size_t nb; int32_t ril = 0; unsigned char * regionEnd = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int xx; int i; struct rpmtd_s sigtd; DIGEST_CTX ctx = NULL; /* Is the blob the right size? */ if (uc > 0 && pvlen != uc) { rasprintf(&buf, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"), (int)uc, (int)il, (int)dl); goto exit; } memset(&entry, 0, sizeof(entry)); memset(&info, 0, sizeof(info)); /* Check (and convert) the 1st tag element. */ xx = headerVerifyInfo(1, dl, pe, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), 0, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag? */ if (!(entry.info.tag == RPMTAG_HEADERIMMUTABLE && entry.info.type == RPM_BIN_TYPE && entry.info.count == REGION_TAG_COUNT)) { rc = RPMRC_NOTFOUND; goto exit; } /* Is the offset within the data area? */ if (entry.info.offset >= dl) { rasprintf(&buf, _("region offset: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag trailer? */ regionEnd = dataStart + entry.info.offset; (void) memcpy(&info, regionEnd, REGION_TAG_COUNT); regionEnd += REGION_TAG_COUNT; xx = headerVerifyInfo(1, dl, &info, &entry.info, 1); if (xx != -1 || !(entry.info.tag == RPMTAG_HEADERIMMUTABLE && entry.info.type == RPM_BIN_TYPE && entry.info.count == REGION_TAG_COUNT)) { rasprintf(&buf, _("region trailer: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } memset(&info, 0, sizeof(info)); /* Is the no. of tags in the region less than the total no. of tags? */ ril = entry.info.offset/sizeof(*pe); if ((entry.info.offset % sizeof(*pe)) || ril > il) { rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il); goto exit; } /* Find a header-only digest/signature tag. */ for (i = ril; i < il; i++) { xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), i, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } switch (entry.info.tag) { case RPMTAG_SHA1HEADER: if (vsflags & RPMVSF_NOSHA1HEADER) break; blen = 0; for (b = dataStart + entry.info.offset; *b != '\0'; b++) { if (strchr("0123456789abcdefABCDEF", *b) == NULL) break; blen++; } if (entry.info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40) { rasprintf(&buf, _("hdr SHA1: BAD, not hex\n")); goto exit; } if (info.tag == 0) { info = entry.info; /* structure assignment */ siglen = blen + 1; } break; case RPMTAG_RSAHEADER: if (vsflags & RPMVSF_NORSAHEADER) break; if (entry.info.type != RPM_BIN_TYPE) { rasprintf(&buf, _("hdr RSA: BAD, not binary\n")); goto exit; } info = entry.info; /* structure assignment */ siglen = info.count; break; case RPMTAG_DSAHEADER: if (vsflags & RPMVSF_NODSAHEADER) break; if (entry.info.type != RPM_BIN_TYPE) { rasprintf(&buf, _("hdr DSA: BAD, not binary\n")); goto exit; } info = entry.info; /* structure assignment */ siglen = info.count; break; default: break; } } rc = RPMRC_NOTFOUND; exit: /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */ if (rc != RPMRC_NOTFOUND) { if (msg) *msg = buf; else free(buf); return rc; } /* If no header-only digest/signature, then do simple sanity check. */ if (info.tag == 0) { verifyinfo_exit: xx = headerVerifyInfo(ril-1, dl, pe+1, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), xx+1, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); rc = RPMRC_FAIL; } else { rasprintf(&buf, "Header sanity check: OK\n"); rc = RPMRC_OK; } if (msg) *msg = buf; else free(buf); return rc; } /* Verify header-only digest/signature. */ dig = pgpNewDig(); if (dig == NULL) goto verifyinfo_exit; sigtd.tag = info.tag; sigtd.type = info.type; sigtd.count = info.count; sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen); sigtd.flags = RPMTD_ALLOCED; switch (info.tag) { case RPMTAG_RSAHEADER: case RPMTAG_DSAHEADER: if ((rc = parsePGP(&sigtd, "header", dig)) != RPMRC_OK) { pgpFreeDig(dig); goto exit; } /* fallthrough */ case RPMTAG_SHA1HEADER: { pgpHashAlgo hashalgo = (info.tag == RPMTAG_SHA1HEADER) ? PGPHASHALGO_SHA1 : dig->signature.hash_algo; ildl[0] = htonl(ril); ildl[1] = (regionEnd - dataStart); ildl[1] = htonl(ildl[1]); ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); b = (unsigned char *) rpm_header_magic; nb = sizeof(rpm_header_magic); (void) rpmDigestUpdate(ctx, b, nb); b = (unsigned char *) ildl; nb = sizeof(ildl); (void) rpmDigestUpdate(ctx, b, nb); b = (unsigned char *) pe; nb = (htonl(ildl[0]) * sizeof(*pe)); (void) rpmDigestUpdate(ctx, b, nb); b = (unsigned char *) dataStart; nb = htonl(ildl[1]); (void) rpmDigestUpdate(ctx, b, nb); } break; default: sigtd.data = _free(sigtd.data); /* Hmm...? */ break; } rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &buf); if (msg) *msg = buf; else free(buf); rpmtdFreeData(&sigtd); pgpFreeDig(dig); rpmDigestFinal(ctx, NULL, NULL, 0); return rc; }
/* * Argument monster to verify header-only signature/digest if there is * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check. */ static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags, int il, int dl, int ril, int rdl, entryInfo pe, unsigned char * dataStart, char **buf) { size_t siglen = 0; rpmRC rc = RPMRC_FAIL; pgpDigParams sig = NULL; struct rpmtd_s sigtd; struct entryInfo_s info, einfo; unsigned int hashalgo = 0; rpmtdReset(&sigtd); memset(&info, 0, sizeof(info)); memset(&einfo, 0, sizeof(einfo)); /* Find a header-only digest/signature tag. */ for (int i = ril; i < il; i++) { if (headerVerifyInfo(1, dl, pe+i, &einfo, 0) != -1) { rasprintf(buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), i, einfo.tag, einfo.type, einfo.offset, einfo.count); goto exit; } switch (einfo.tag) { case RPMTAG_SHA1HEADER: { size_t blen = 0; unsigned const char * b; if (vsflags & RPMVSF_NOSHA1HEADER) break; for (b = dataStart + einfo.offset; *b != '\0'; b++) { if (strchr("0123456789abcdefABCDEF", *b) == NULL) break; blen++; } if (einfo.type != RPM_STRING_TYPE || *b != '\0' || blen != 40) { rasprintf(buf, _("hdr SHA1: BAD, not hex\n")); goto exit; } if (info.tag == 0) { info = einfo; /* structure assignment */ siglen = blen + 1; } } break; case RPMTAG_RSAHEADER: if (vsflags & RPMVSF_NORSAHEADER) break; if (einfo.type != RPM_BIN_TYPE) { rasprintf(buf, _("hdr RSA: BAD, not binary\n")); goto exit; } info = einfo; /* structure assignment */ siglen = info.count; break; case RPMTAG_DSAHEADER: if (vsflags & RPMVSF_NODSAHEADER) break; if (einfo.type != RPM_BIN_TYPE) { rasprintf(buf, _("hdr DSA: BAD, not binary\n")); goto exit; } info = einfo; /* structure assignment */ siglen = info.count; break; default: break; } } /* No header-only digest/signature found, get outta here */ if (info.tag == 0) { rc = RPMRC_NOTFOUND; goto exit; } sigtd.tag = info.tag; sigtd.type = info.type; sigtd.count = info.count; sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen); sigtd.flags = RPMTD_ALLOCED; switch (info.tag) { case RPMTAG_RSAHEADER: case RPMTAG_DSAHEADER: if (parsePGPSig(&sigtd, "header", NULL, &sig)) goto exit; hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO); break; case RPMTAG_SHA1HEADER: hashalgo = PGPHASHALGO_SHA1; break; default: break; } if (hashalgo) { DIGEST_CTX ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); int32_t ildl[2] = { htonl(ril), htonl(rdl) }; rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, ildl, sizeof(ildl)); rpmDigestUpdate(ctx, pe, (ril * sizeof(*pe))); rpmDigestUpdate(ctx, dataStart, rdl); rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf); rpmDigestFinal(ctx, NULL, NULL, 0); } exit: rpmtdFreeData(&sigtd); pgpDigParamsFree(sig); return rc; }
/* Build pubkey header. */ static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp) { Header h = headerNew(); const char * afmt = "%{pubkeys:armor}"; const char * group = "Public Keys"; const char * license = "pubkey"; const char * buildhost = "localhost"; const char * userid; rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL); uint32_t zero = 0; uint32_t keytime = 0; pgpDig dig = NULL; pgpDigParams pubp = NULL; char * d = NULL; char * enc = NULL; char * n = NULL; char * u = NULL; char * v = NULL; char * r = NULL; char * evr = NULL; int rc = -1; if ((enc = rpmPubkeyBase64(key)) == NULL) goto exit; if ((dig = rpmPubkeyDig(key)) == NULL) goto exit; if ((pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY)) == NULL) goto exit; /* Build header elements. */ v = pgpHexStr(pubp->signid, sizeof(pubp->signid)); r = pgpHexStr(pubp->time, sizeof(pubp->time)); userid = pubp->userid ? pubp->userid : "none"; keytime = pgpGrab(pubp->time, sizeof(pubp->time)); rasprintf(&n, "gpg(%s)", v+8); rasprintf(&u, "gpg(%s)", userid); rasprintf(&evr, "%d:%s-%s", pubp->version, v, r); headerPutString(h, RPMTAG_PUBKEYS, enc); if ((d = headerFormat(h, afmt, NULL)) == NULL) goto exit; headerPutString(h, RPMTAG_NAME, "gpg-pubkey"); headerPutString(h, RPMTAG_VERSION, v+8); headerPutString(h, RPMTAG_RELEASE, r); headerPutString(h, RPMTAG_DESCRIPTION, d); headerPutString(h, RPMTAG_GROUP, group); headerPutString(h, RPMTAG_LICENSE, license); headerPutString(h, RPMTAG_SUMMARY, u); headerPutString(h, RPMTAG_PACKAGER, userid); headerPutUint32(h, RPMTAG_SIZE, &zero, 1); headerPutString(h, RPMTAG_PROVIDENAME, u); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_PROVIDENAME, n); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION); headerPutString(h, RPMTAG_BUILDHOST, buildhost); headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1); headerPutString(h, RPMTAG_SOURCERPM, "(none)"); /* Reload the lot to immutable region and stomp sha1 digest on it */ h = headerReload(h, RPMTAG_HEADERIMMUTABLE); if (h != NULL) { char *sha1 = NULL; unsigned int blen = 0; const void *blob = headerExport(h, &blen); /* XXX FIXME: bah, this code is repeated in way too many places */ DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, blob, blen); rpmDigestFinal(ctx, (void **)&sha1, NULL, 1); if (sha1) { headerPutString(h, RPMTAG_SHA1HEADER, sha1); *hdrp = headerLink(h); rc = 0; } free(sha1); } exit: headerFree(h); pgpFreeDig(dig); free(n); free(u); free(v); free(r); free(evr); free(enc); free(d); return rc; }
int main(int argc, char *argv[]) { pgpImplVecs_t * testImplVecs = &rpmnssImplVecs; pgpDig dig; pgpDigParams pubp; rpmbc bc; int printing = -1; int rc; pgpImplVecs = &rpmbcImplVecs; dig = pgpDigNew(RPMVSF_DEFAULT, 0); pubp = pgpGetPubkey(dig); bc = dig->impl; mpbzero(&bc->p); mpbsethex(&bc->p, fips_p); mpbzero(&bc->q); mpbsethex(&bc->q, fips_q); mpnzero(&bc->g); mpnsethex(&bc->g, fips_g); mpnzero(&bc->y); mpnsethex(&bc->y, fips_y); mpnzero(&bc->r); mpnsethex(&bc->r, fips_r); mpnzero(&bc->s); mpnsethex(&bc->s, fips_s); mpnzero(&bc->hm); mpnsethex(&bc->hm, fips_hm); pubp->pubkey_algo = PGPPUBKEYALGO_DSA; /* XXX assert? */ rc = pgpImplVerify(dig); fprintf(stderr, "=============================== DSA FIPS-186-1: rc %d\n", rc); dig = pgpDigFree(dig); pgpImplVecs = testImplVecs; dig = pgpDigNew(RPMVSF_DEFAULT, 0); pubp = pgpGetPubkey(dig); _pgp_debug = 1; _pgp_print = 1; fprintf(stderr, "=============================== DSA Public Key\n"); if ((rc = doit(DSApub, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); fprintf(stderr, "=============================== DSA Signature of \"%s\"\n", str); if ((rc = doit(DSAsig, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); pgpDigParams dsig = pgpGetSignature(dig); rpmDigestUpdate(ctx, str, strlen(str)); rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen); (void) pgpImplSetDSA(ctx, dig, dsig); } pubp->pubkey_algo = PGPPUBKEYALGO_DSA; /* XXX assert? */ rc = pgpImplVerify(dig); fprintf(stderr, "=============================== DSA verify: rc %d\n", rc); dig = pgpDigFree(dig); pgpImplVecs = testImplVecs; dig = pgpDigNew(RPMVSF_DEFAULT, 0); pubp = pgpGetPubkey(dig); _pgp_debug = 1; _pgp_print = 1; fprintf(stderr, "=============================== RSA Public Key\n"); if ((rc = doit(RSApub, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); fprintf(stderr, "=============================== RSA Signature of \"%s\"\n", str); if ((rc = doit(RSAsig, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); pgpDigParams dsig = pgpGetSignature(dig); rpmDigestUpdate(ctx, str, strlen(str)); rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen); (void) pgpImplSetRSA(ctx, dig, dsig); } pubp->pubkey_algo = PGPPUBKEYALGO_RSA; /* XXX assert? */ rc = pgpImplVerify(dig); fprintf(stderr, "=============================== RSA verify: rc %d\n", rc); dig = pgpDigFree(dig); pgpImplVecs = testImplVecs; dig = pgpDigNew(RPMVSF_DEFAULT, 0); pubp = pgpGetPubkey(dig); _pgp_debug = 1; _pgp_print = 1; fprintf(stderr, "=============================== ECDSA Public Key\n"); if ((rc = doit(ECDSApub, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); fprintf(stderr, "=============================== ECDSA Signature of \"%s\"\n", str); if ((rc = doit(ECDSAsig, dig, printing)) != 0) fprintf(stderr, "==> FAILED: rc %d\n", rc); { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA256, RPMDIGEST_NONE); pgpDigParams dsig = pgpGetSignature(dig); rpmDigestUpdate(ctx, str, strlen(str)); rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen); (void) pgpImplSetECDSA(ctx, dig, dsig); } pubp->pubkey_algo = PGPPUBKEYALGO_ECDSA; /* XXX assert? */ rc = pgpImplVerify(dig); fprintf(stderr, "=============================== ECDSA verify: rc %d\n", rc); dig = pgpDigFree(dig); if (pgpImplVecs == &rpmsslImplVecs) NSS_Shutdown(); return rc; }