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