Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / sign / rpmsignfiles.c
1 /**
2  * Copyright (C) 2014 IBM Corporation
3  *
4  * Author: Fionnuala Gunter <fin@linux.vnet.ibm.com>
5  */
6
7 #include "system.h"
8 #include "imaevm.h"
9
10 #include <rpm/rpmlog.h>         /* rpmlog */
11 #include <rpm/rpmstring.h>      /* rnibble */
12 #include <rpm/rpmpgp.h>         /* rpmDigestLength */
13 #include "lib/header.h"         /* HEADERGET_MINMEM */
14 #include "lib/rpmtypes.h"       /* rpmRC */
15
16 #include "sign/rpmsignfiles.h"
17
18 #define MAX_SIGNATURE_LENGTH 1024
19
20 static const char *hash_algo_name[] = {
21     [PGPHASHALGO_MD5]          = "md5",
22     [PGPHASHALGO_SHA1]         = "sha1",
23     [PGPHASHALGO_RIPEMD160]    = "rmd160",
24     [PGPHASHALGO_MD2]          = "md2",
25     [PGPHASHALGO_TIGER192]     = "tgr192",
26     [PGPHASHALGO_HAVAL_5_160]  = "haval5160",
27     [PGPHASHALGO_SHA256]       = "sha256",
28     [PGPHASHALGO_SHA384]       = "sha384",
29     [PGPHASHALGO_SHA512]       = "sha512",
30     [PGPHASHALGO_SHA224]       = "sha224",
31 };
32
33 #define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))
34
35 static char *signFile(const char *algo, const char *fdigest, int diglen,
36 const char *key, char *keypass)
37 {
38     char *fsignature;
39     unsigned char digest[diglen];
40     unsigned char signature[MAX_SIGNATURE_LENGTH];
41     int siglen;
42
43     /* convert file digest hex to binary */
44     memset(digest, 0, diglen);
45     /* some entries don't have a digest - we return an empty signature */
46     if (strlen(fdigest) != diglen * 2)
47         return strdup("");
48
49     for (int i = 0; i < diglen; ++i, fdigest += 2)
50         digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
51
52     /* prepare file signature */
53     memset(signature, 0, MAX_SIGNATURE_LENGTH);
54     signature[0] = '\x03';
55
56     /* calculate file signature */
57     siglen = sign_hash(algo, digest, diglen, key, keypass, signature+1);
58     if (siglen < 0) {
59         rpmlog(RPMLOG_ERR, _("sign_hash failed\n"));
60         return NULL;
61     }
62
63     /* convert file signature binary to hex */
64     fsignature = pgpHexStr(signature, siglen+1);
65     return fsignature;
66 }
67
68 static uint32_t signatureLength(const char *algo, int diglen, const char *key,
69 char *keypass)
70 {
71     unsigned char digest[diglen];
72     unsigned char signature[MAX_SIGNATURE_LENGTH];
73
74     memset(digest, 0, diglen);
75     memset(signature, 0, MAX_SIGNATURE_LENGTH);
76     signature[0] = '\x03';
77
78     uint32_t siglen = sign_hash(algo, digest, diglen, key, keypass,
79                                 signature+1);
80     return siglen + 1;
81 }
82
83 rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
84 {
85     struct rpmtd_s digests;
86     int algo;
87     int diglen;
88     uint32_t siglen;
89     const char *algoname;
90     const char *digest;
91     char *signature;
92     rpmRC rc = RPMRC_OK;
93
94     algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);
95     if (!algo) {
96         /* use default algorithm */
97         algo = PGPHASHALGO_MD5;
98     } else if (algo < 0 || algo >= ARRAY_SIZE(hash_algo_name)) {
99         rpmlog(RPMLOG_ERR, _("File digest algorithm id is invalid"));
100         return RPMRC_FAIL;
101     }
102
103     diglen = rpmDigestLength(algo);
104     algoname = hash_algo_name[algo];
105     if (!algoname) {
106         rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));
107         return RPMRC_FAIL;
108     }
109
110     headerDel(h, RPMTAG_FILESIGNATURELENGTH);
111     headerDel(h, RPMTAG_FILESIGNATURES);
112     siglen = signatureLength(algoname, diglen, key, keypass);
113     headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1);
114
115     headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
116     while ((digest = rpmtdNextString(&digests))) {
117         signature = signFile(algoname, digest, diglen, key, keypass);
118         if (!signature) {
119             rpmlog(RPMLOG_ERR, _("signFile failed\n"));
120             rc = RPMRC_FAIL;
121             goto exit;
122         }
123         if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
124             free(signature);
125             rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
126             rc = RPMRC_FAIL;
127             goto exit;
128         }
129         free(signature);
130     }
131
132 exit:
133     rpmtdFreeData(&digests);
134     return rc;
135 }