1 /** \ingroup signature
2 * \file lib/signature.c
3 */
4
5 #include "system.h"
6
7 #include <inttypes.h>
8 #include <netinet/in.h>
9
10 #include <rpm/rpmtypes.h>
11 #include <rpm/rpmstring.h>
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmmacro.h>
15
16 #include "lib/rpmlead.h"
17 #include "lib/header_internal.h"
18 #include "lib/signature.h"
19
20 #include "debug.h"
21
22 /**
23 * Print package size (debug purposes only)
24 * @param fd package file handle
25 * @param sigh signature header
26 */
printSize(FD_t fd,Header sigh)27 static void printSize(FD_t fd, Header sigh)
28 {
29 struct stat st;
30 int fdno = Fileno(fd);
31 size_t siglen = headerSizeof(sigh, HEADER_MAGIC_YES);
32 size_t pad = (8 - (siglen % 8)) % 8; /* 8-byte pad */
33 struct rpmtd_s sizetag;
34 rpm_loff_t datalen = 0;
35
36 /* Print package component sizes. */
37 if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) {
38 rpm_loff_t *tsize = rpmtdGetUint64(&sizetag);
39 datalen = (tsize) ? *tsize : 0;
40 } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) {
41 rpm_off_t *tsize = rpmtdGetUint32(&sizetag);
42 datalen = (tsize) ? *tsize : 0;
43 }
44 rpmtdFreeData(&sizetag);
45
46 rpmlog(RPMLOG_DEBUG,
47 "Expected size: %12" PRIu64 \
48 " = lead(%d)+sigs(%zd)+pad(%zd)+data(%" PRIu64 ")\n",
49 RPMLEAD_SIZE+siglen+pad+datalen,
50 RPMLEAD_SIZE, siglen, pad, datalen);
51
52 if (fstat(fdno, &st) == 0) {
53 rpmlog(RPMLOG_DEBUG,
54 " Actual size: %12" PRIu64 "\n", (rpm_loff_t) st.st_size);
55 }
56 }
57
rpmReadSignature(FD_t fd,Header * sighp,char ** msg)58 rpmRC rpmReadSignature(FD_t fd, Header * sighp, char ** msg)
59 {
60 char *buf = NULL;
61 struct hdrblob_s blob;
62 Header sigh = NULL;
63 rpmRC rc = RPMRC_FAIL; /* assume failure */
64
65 if (sighp)
66 *sighp = NULL;
67
68 if (hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, &blob, &buf) != RPMRC_OK)
69 goto exit;
70
71 /* OK, blob looks sane, load the header. */
72 if (hdrblobImport(&blob, 0, &sigh, &buf) != RPMRC_OK)
73 goto exit;
74
75 printSize(fd, sigh);
76 rc = RPMRC_OK;
77
78 exit:
79 if (sighp && sigh && rc == RPMRC_OK)
80 *sighp = headerLink(sigh);
81 headerFree(sigh);
82
83 if (msg != NULL) {
84 *msg = buf;
85 } else {
86 free(buf);
87 }
88
89 return rc;
90 }
91
rpmWriteSignature(FD_t fd,Header sigh)92 int rpmWriteSignature(FD_t fd, Header sigh)
93 {
94 static const uint8_t zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
95 int sigSize, pad;
96 int rc;
97
98 rc = headerWrite(fd, sigh, HEADER_MAGIC_YES);
99 if (rc)
100 return rc;
101
102 sigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
103 pad = (8 - (sigSize % 8)) % 8;
104 if (pad) {
105 if (Fwrite(zeros, sizeof(zeros[0]), pad, fd) != pad)
106 rc = 1;
107 }
108 rpmlog(RPMLOG_DEBUG, "Signature: size(%d)+pad(%d)\n", sigSize, pad);
109 return rc;
110 }
111
rpmGenerateSignature(char * SHA256,char * SHA1,uint8_t * MD5,rpm_loff_t size,rpm_loff_t payloadSize,FD_t fd)112 rpmRC rpmGenerateSignature(char *SHA256, char *SHA1, uint8_t *MD5,
113 rpm_loff_t size, rpm_loff_t payloadSize, FD_t fd)
114 {
115 Header sig = headerNew();
116 struct rpmtd_s td;
117 rpmRC rc = RPMRC_OK;
118 char *reservedSpace;
119 int spaceSize = 32; /* always reserve a bit of space */
120 int gpgSize = rpmExpandNumeric("%{__gpg_reserved_space}");
121 rpm_off_t size32 = size;
122 rpm_off_t payloadSize32 = payloadSize;
123
124 /* Prepare signature */
125 if (SHA256) {
126 rpmtdReset(&td);
127 td.tag = RPMSIGTAG_SHA256;
128 td.count = 1;
129 td.type = RPM_STRING_TYPE;
130 td.data = SHA256;
131 headerPut(sig, &td, HEADERPUT_DEFAULT);
132 }
133
134 if (SHA1) {
135 rpmtdReset(&td);
136 td.tag = RPMSIGTAG_SHA1;
137 td.count = 1;
138 td.type = RPM_STRING_TYPE;
139 td.data = SHA1;
140 headerPut(sig, &td, HEADERPUT_DEFAULT);
141 }
142
143 if (MD5) {
144 rpmtdReset(&td);
145 td.tag = RPMSIGTAG_MD5;
146 td.count = 16;
147 td.type = RPM_BIN_TYPE;
148 td.data = MD5;
149 headerPut(sig, &td, HEADERPUT_DEFAULT);
150 }
151
152 rpmtdReset(&td);
153 td.count = 1;
154 td.type = RPM_INT32_TYPE;
155
156 td.tag = RPMSIGTAG_PAYLOADSIZE;
157 td.data = &payloadSize32;
158 headerPut(sig, &td, HEADERPUT_DEFAULT);
159
160 td.tag = RPMSIGTAG_SIZE;
161 td.data = &size32;
162 headerPut(sig, &td, HEADERPUT_DEFAULT);
163
164 if (size >= UINT32_MAX || payloadSize >= UINT32_MAX) {
165 /*
166 * Put the 64bit size variants into the header, but
167 * modify spaceSize so that the resulting header has
168 * the same size. Note that this only works if all tags
169 * with a lower number than RPMSIGTAG_RESERVEDSPACE are
170 * already added and no tag with a higher number is
171 * added yet.
172 */
173 rpm_loff_t p = payloadSize;
174 rpm_loff_t s = size;
175 int newsigSize, oldsigSize;
176
177 oldsigSize = headerSizeof(sig, HEADER_MAGIC_YES);
178
179 headerDel(sig, RPMSIGTAG_PAYLOADSIZE);
180 headerDel(sig, RPMSIGTAG_SIZE);
181
182 td.type = RPM_INT64_TYPE;
183
184 td.tag = RPMSIGTAG_LONGARCHIVESIZE;
185 td.data = &p;
186 headerPut(sig, &td, HEADERPUT_DEFAULT);
187
188 td.tag = RPMSIGTAG_LONGSIZE;
189 td.data = &s;
190 headerPut(sig, &td, HEADERPUT_DEFAULT);
191
192 newsigSize = headerSizeof(sig, HEADER_MAGIC_YES);
193 spaceSize -= newsigSize - oldsigSize;
194 }
195
196 if (gpgSize > 0)
197 spaceSize += gpgSize;
198
199 if (spaceSize > 0) {
200 reservedSpace = xcalloc(spaceSize, sizeof(char));
201 rpmtdReset(&td);
202 td.tag = RPMSIGTAG_RESERVEDSPACE;
203 td.count = spaceSize;
204 td.type = RPM_BIN_TYPE;
205 td.data = reservedSpace;
206 headerPut(sig, &td, HEADERPUT_DEFAULT);
207 free(reservedSpace);
208 }
209
210 /* Reallocate the signature into one contiguous region. */
211 sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
212 if (sig == NULL) { /* XXX can't happen */
213 rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
214 rc = RPMRC_FAIL;
215 goto exit;
216 }
217
218 /* Write the signature section into the package. */
219 if (rpmWriteSignature(fd, sig)) {
220 rc = RPMRC_FAIL;
221 goto exit;
222 }
223
224 exit:
225 headerFree(sig);
226 return rc;
227 }
228
229
230