1df8bdeb3Sjohnz /*
2df8bdeb3Sjohnz * CDDL HEADER START
3df8bdeb3Sjohnz *
4df8bdeb3Sjohnz * The contents of this file are subject to the terms of the
5df8bdeb3Sjohnz * Common Development and Distribution License (the "License").
6df8bdeb3Sjohnz * You may not use this file except in compliance with the License.
7df8bdeb3Sjohnz *
8df8bdeb3Sjohnz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9df8bdeb3Sjohnz * or http://www.opensolaris.org/os/licensing.
10df8bdeb3Sjohnz * See the License for the specific language governing permissions
11df8bdeb3Sjohnz * and limitations under the License.
12df8bdeb3Sjohnz *
13df8bdeb3Sjohnz * When distributing Covered Code, include this CDDL HEADER in each
14df8bdeb3Sjohnz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15df8bdeb3Sjohnz * If applicable, add the following below this CDDL HEADER, with the
16df8bdeb3Sjohnz * fields enclosed by brackets "[]" replaced with your own identifying
17df8bdeb3Sjohnz * information: Portions Copyright [yyyy] [name of copyright owner]
18df8bdeb3Sjohnz *
19df8bdeb3Sjohnz * CDDL HEADER END
20df8bdeb3Sjohnz */
21df8bdeb3Sjohnz
22df8bdeb3Sjohnz /*
23*9b009fc1SValerie Bubb Fenwick * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24df8bdeb3Sjohnz */
25df8bdeb3Sjohnz
26df8bdeb3Sjohnz #define ELF_TARGET_ALL /* get definitions of all section flags */
27df8bdeb3Sjohnz
28df8bdeb3Sjohnz #include <sys/types.h>
29df8bdeb3Sjohnz #include <sys/stat.h>
30df8bdeb3Sjohnz #include <fcntl.h>
31df8bdeb3Sjohnz #include <unistd.h>
32df8bdeb3Sjohnz #include <strings.h>
33df8bdeb3Sjohnz #include <stddef.h>
34df8bdeb3Sjohnz #include <stdlib.h>
35df8bdeb3Sjohnz #include <libintl.h>
36df8bdeb3Sjohnz #include <dirent.h>
37df8bdeb3Sjohnz #include <errno.h>
38df8bdeb3Sjohnz #include <libelf.h>
39df8bdeb3Sjohnz #include <gelf.h>
40df8bdeb3Sjohnz #include <cryptoutil.h>
41df8bdeb3Sjohnz #include <sha1.h>
42df8bdeb3Sjohnz #include <sys/crypto/elfsign.h>
43df8bdeb3Sjohnz #include <libelfsign.h>
44df8bdeb3Sjohnz
45df8bdeb3Sjohnz #ifndef SHA1_DIGEST_LENGTH
46df8bdeb3Sjohnz #define SHA1_DIGEST_LENGTH 20
47df8bdeb3Sjohnz #endif /* SHA1_DIGEST_LENGTH */
48df8bdeb3Sjohnz
49df8bdeb3Sjohnz const char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION;
50df8bdeb3Sjohnz const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
51df8bdeb3Sjohnz
52df8bdeb3Sjohnz static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
53df8bdeb3Sjohnz Elf_Scn *scn, uint64_t new_size);
54df8bdeb3Sjohnz static uint32_t elfsign_switch_uint32(uint32_t i);
55df8bdeb3Sjohnz static ELFsign_status_t elfsign_switch(ELFsign_t ess,
56df8bdeb3Sjohnz struct filesignatures *fssp, enum ES_ACTION action);
57df8bdeb3Sjohnz
58df8bdeb3Sjohnz struct filesig_extraction {
59df8bdeb3Sjohnz filesig_vers_t fsx_version;
60df8bdeb3Sjohnz char *fsx_format;
61df8bdeb3Sjohnz char fsx_signer_DN[ELFCERT_MAX_DN_LEN];
62df8bdeb3Sjohnz size_t fsx_signer_DN_len;
63df8bdeb3Sjohnz uchar_t fsx_signature[SIG_MAX_LENGTH];
64df8bdeb3Sjohnz size_t fsx_sig_len;
65df8bdeb3Sjohnz char fsx_sig_oid[100];
66df8bdeb3Sjohnz size_t fsx_sig_oid_len;
67df8bdeb3Sjohnz time_t fsx_time;
68df8bdeb3Sjohnz };
69df8bdeb3Sjohnz
70df8bdeb3Sjohnz static char *
version_to_str(filesig_vers_t v)71df8bdeb3Sjohnz version_to_str(filesig_vers_t v)
72df8bdeb3Sjohnz {
73df8bdeb3Sjohnz char *ret;
74df8bdeb3Sjohnz
75df8bdeb3Sjohnz switch (v) {
76df8bdeb3Sjohnz case FILESIG_VERSION1:
77df8bdeb3Sjohnz ret = "VERSION1";
78df8bdeb3Sjohnz break;
79df8bdeb3Sjohnz case FILESIG_VERSION2:
80df8bdeb3Sjohnz ret = "VERSION2";
81df8bdeb3Sjohnz break;
82df8bdeb3Sjohnz case FILESIG_VERSION3:
83df8bdeb3Sjohnz ret = "VERSION3";
84df8bdeb3Sjohnz break;
85df8bdeb3Sjohnz case FILESIG_VERSION4:
86df8bdeb3Sjohnz ret = "VERSION4";
87df8bdeb3Sjohnz break;
88df8bdeb3Sjohnz default:
89df8bdeb3Sjohnz ret = "UNKNOWN";
90df8bdeb3Sjohnz break;
91df8bdeb3Sjohnz }
92df8bdeb3Sjohnz return (ret);
93df8bdeb3Sjohnz }
94df8bdeb3Sjohnz
95df8bdeb3Sjohnz /*
96df8bdeb3Sjohnz * Update filesignatures to include the v1/v2 filesig,
97df8bdeb3Sjohnz * composed of signer DN, signature, and OID.
98df8bdeb3Sjohnz */
99df8bdeb3Sjohnz static struct filesignatures *
filesig_insert_dso(struct filesignatures * fssp,filesig_vers_t version,const char * dn,int dn_len,const uchar_t * sig,int sig_len,const char * oid,int oid_len)100df8bdeb3Sjohnz filesig_insert_dso(struct filesignatures *fssp,
101df8bdeb3Sjohnz filesig_vers_t version,
102df8bdeb3Sjohnz const char *dn,
103df8bdeb3Sjohnz int dn_len,
104df8bdeb3Sjohnz const uchar_t *sig,
105df8bdeb3Sjohnz int sig_len,
106df8bdeb3Sjohnz const char *oid,
107df8bdeb3Sjohnz int oid_len)
108df8bdeb3Sjohnz {
109df8bdeb3Sjohnz struct filesig *fsgp;
110df8bdeb3Sjohnz char *fsdatap;
111df8bdeb3Sjohnz
112df8bdeb3Sjohnz if (oid == NULL) {
113df8bdeb3Sjohnz /*
114df8bdeb3Sjohnz * This OID is used for the rsa_md5_sha1 format signature also.
115df8bdeb3Sjohnz * This use is historical, and is hence continued,
116df8bdeb3Sjohnz * despite its lack of technical accuracy.
117df8bdeb3Sjohnz */
118df8bdeb3Sjohnz oid = OID_sha1WithRSAEncryption;
119df8bdeb3Sjohnz oid_len = strlen(oid);
120df8bdeb3Sjohnz }
121df8bdeb3Sjohnz
122df8bdeb3Sjohnz /*
123df8bdeb3Sjohnz * for now, always insert a single-signature signature block
124df8bdeb3Sjohnz */
125df8bdeb3Sjohnz if (fssp != NULL)
126df8bdeb3Sjohnz free(fssp);
127df8bdeb3Sjohnz fssp = (struct filesignatures *)
128df8bdeb3Sjohnz malloc(filesig_ALIGN(sizeof (struct filesignatures) +
129df8bdeb3Sjohnz dn_len + sig_len + oid_len));
130df8bdeb3Sjohnz if (fssp == NULL)
131df8bdeb3Sjohnz return (fssp);
132df8bdeb3Sjohnz
133df8bdeb3Sjohnz fssp->filesig_cnt = 1;
134df8bdeb3Sjohnz fssp->filesig_pad = 0; /* reserve for future use */
135df8bdeb3Sjohnz
136df8bdeb3Sjohnz fsgp = &fssp->filesig_sig;
137df8bdeb3Sjohnz fsgp->filesig_size = sizeof (struct filesig) +
138df8bdeb3Sjohnz dn_len + sig_len + oid_len;
139df8bdeb3Sjohnz fsgp->filesig_version = version;
140df8bdeb3Sjohnz switch (version) {
141df8bdeb3Sjohnz case FILESIG_VERSION1:
142df8bdeb3Sjohnz case FILESIG_VERSION2:
143df8bdeb3Sjohnz fsgp->filesig_size -= sizeof (struct filesig) -
144df8bdeb3Sjohnz offsetof(struct filesig, filesig_v1_data[0]);
145df8bdeb3Sjohnz fsgp->filesig_v1_dnsize = dn_len;
146df8bdeb3Sjohnz fsgp->filesig_v1_sigsize = sig_len;
147df8bdeb3Sjohnz fsgp->filesig_v1_oidsize = oid_len;
148df8bdeb3Sjohnz fsdatap = &fsgp->filesig_v1_data[0];
149df8bdeb3Sjohnz break;
150df8bdeb3Sjohnz case FILESIG_VERSION3:
151df8bdeb3Sjohnz case FILESIG_VERSION4:
152df8bdeb3Sjohnz fsgp->filesig_size -= sizeof (struct filesig) -
153df8bdeb3Sjohnz offsetof(struct filesig, filesig_v3_data[0]);
154df8bdeb3Sjohnz fsgp->filesig_v3_time = time(NULL);
155df8bdeb3Sjohnz fsgp->filesig_v3_dnsize = dn_len;
156df8bdeb3Sjohnz fsgp->filesig_v3_sigsize = sig_len;
157df8bdeb3Sjohnz fsgp->filesig_v3_oidsize = oid_len;
158df8bdeb3Sjohnz fsdatap = &fsgp->filesig_v3_data[0];
159df8bdeb3Sjohnz break;
160df8bdeb3Sjohnz default:
161df8bdeb3Sjohnz cryptodebug("filesig_insert_dso: unknown version: %d",
162df8bdeb3Sjohnz version);
163df8bdeb3Sjohnz free(fssp);
164df8bdeb3Sjohnz return (NULL);
165df8bdeb3Sjohnz }
166df8bdeb3Sjohnz (void) memcpy(fsdatap, dn, dn_len);
167df8bdeb3Sjohnz fsdatap += dn_len;
168df8bdeb3Sjohnz (void) memcpy(fsdatap, (char *)sig, sig_len);
169df8bdeb3Sjohnz fsdatap += sig_len;
170df8bdeb3Sjohnz (void) memcpy(fsdatap, oid, oid_len);
171df8bdeb3Sjohnz fsdatap += oid_len;
172df8bdeb3Sjohnz fsgp = filesig_next(fsgp);
173df8bdeb3Sjohnz (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
174df8bdeb3Sjohnz
175df8bdeb3Sjohnz return (fssp);
176df8bdeb3Sjohnz }
177df8bdeb3Sjohnz
178df8bdeb3Sjohnz /*
179df8bdeb3Sjohnz * filesig_extract - extract filesig structure to internal form
180df8bdeb3Sjohnz */
181df8bdeb3Sjohnz static filesig_vers_t
filesig_extract(struct filesig * fsgp,struct filesig_extraction * fsxp)182df8bdeb3Sjohnz filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
183df8bdeb3Sjohnz {
184df8bdeb3Sjohnz char *fsdp;
185df8bdeb3Sjohnz
186df8bdeb3Sjohnz #define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \
187df8bdeb3Sjohnz len_var = len_limit; \
188df8bdeb3Sjohnz if (len_var > fsgp->field) \
189df8bdeb3Sjohnz len_var = fsgp->field; \
190df8bdeb3Sjohnz (void) memcpy(data_var, cp, len_var); \
191df8bdeb3Sjohnz cp += fsgp->field; }
192df8bdeb3Sjohnz #define filesig_extract_str(cp, field, data_var, len_var) \
193df8bdeb3Sjohnz filesig_extract_common(cp, field, data_var, len_var, \
194df8bdeb3Sjohnz sizeof (data_var) - 1); \
195df8bdeb3Sjohnz data_var[len_var] = '\0';
196df8bdeb3Sjohnz #define filesig_extract_opaque(cp, field, data_var, len_var) \
197df8bdeb3Sjohnz filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
198df8bdeb3Sjohnz
199df8bdeb3Sjohnz fsxp->fsx_version = fsgp->filesig_version;
200df8bdeb3Sjohnz cryptodebug("filesig_extract: version=%s",
201df8bdeb3Sjohnz version_to_str(fsxp->fsx_version));
202df8bdeb3Sjohnz switch (fsxp->fsx_version) {
203df8bdeb3Sjohnz case FILESIG_VERSION1:
204df8bdeb3Sjohnz case FILESIG_VERSION2:
205df8bdeb3Sjohnz /*
206df8bdeb3Sjohnz * extract VERSION1 DN, signature, and OID
207df8bdeb3Sjohnz */
208df8bdeb3Sjohnz fsdp = fsgp->filesig_v1_data;
209df8bdeb3Sjohnz fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
210df8bdeb3Sjohnz fsxp->fsx_time = 0;
211df8bdeb3Sjohnz filesig_extract_str(fsdp, filesig_v1_dnsize,
212df8bdeb3Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
213df8bdeb3Sjohnz filesig_extract_opaque(fsdp, filesig_v1_sigsize,
214df8bdeb3Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len);
215df8bdeb3Sjohnz filesig_extract_str(fsdp, filesig_v1_oidsize,
216df8bdeb3Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
217df8bdeb3Sjohnz break;
218df8bdeb3Sjohnz case FILESIG_VERSION3:
219df8bdeb3Sjohnz case FILESIG_VERSION4:
220df8bdeb3Sjohnz fsdp = fsgp->filesig_v3_data;
221df8bdeb3Sjohnz fsxp->fsx_format = ES_FMT_RSA_SHA1;
222df8bdeb3Sjohnz fsxp->fsx_time = fsgp->filesig_v3_time;
223df8bdeb3Sjohnz filesig_extract_str(fsdp, filesig_v3_dnsize,
224df8bdeb3Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
225df8bdeb3Sjohnz filesig_extract_opaque(fsdp, filesig_v3_sigsize,
226df8bdeb3Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len);
227df8bdeb3Sjohnz filesig_extract_str(fsdp, filesig_v3_oidsize,
228df8bdeb3Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
229df8bdeb3Sjohnz break;
230df8bdeb3Sjohnz default:
231df8bdeb3Sjohnz break;
232df8bdeb3Sjohnz }
233df8bdeb3Sjohnz
234df8bdeb3Sjohnz return (fsxp->fsx_version);
235df8bdeb3Sjohnz }
236df8bdeb3Sjohnz
237df8bdeb3Sjohnz ELFsign_status_t
elfsign_begin(const char * filename,enum ES_ACTION action,ELFsign_t * essp)238df8bdeb3Sjohnz elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
239df8bdeb3Sjohnz {
240df8bdeb3Sjohnz Elf_Cmd elfcmd;
241df8bdeb3Sjohnz int oflags = 0;
242df8bdeb3Sjohnz short l_type;
243df8bdeb3Sjohnz ELFsign_t ess;
244df8bdeb3Sjohnz struct stat stb;
245df8bdeb3Sjohnz union {
246df8bdeb3Sjohnz char c[2];
247df8bdeb3Sjohnz short s;
248df8bdeb3Sjohnz } uorder;
249df8bdeb3Sjohnz GElf_Ehdr elfehdr;
250df8bdeb3Sjohnz char *ident;
251df8bdeb3Sjohnz
252df8bdeb3Sjohnz switch (action) {
253df8bdeb3Sjohnz case ES_GET:
254df8bdeb3Sjohnz case ES_GET_CRYPTO:
25573556491SAnthony Scarpino case ES_GET_FIPS140:
256df8bdeb3Sjohnz cryptodebug("elfsign_begin for get");
257df8bdeb3Sjohnz elfcmd = ELF_C_READ;
258df8bdeb3Sjohnz oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
259df8bdeb3Sjohnz l_type = F_RDLCK;
260df8bdeb3Sjohnz break;
261df8bdeb3Sjohnz case ES_UPDATE_RSA_MD5_SHA1:
262df8bdeb3Sjohnz case ES_UPDATE_RSA_SHA1:
263df8bdeb3Sjohnz cryptodebug("elfsign_begin for update");
264df8bdeb3Sjohnz elfcmd = ELF_C_RDWR;
265df8bdeb3Sjohnz oflags = O_RDWR | O_NOCTTY | O_NDELAY;
266df8bdeb3Sjohnz l_type = F_WRLCK;
267df8bdeb3Sjohnz break;
268df8bdeb3Sjohnz default:
269df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
270df8bdeb3Sjohnz }
271df8bdeb3Sjohnz
272df8bdeb3Sjohnz if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
273df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
274df8bdeb3Sjohnz }
275df8bdeb3Sjohnz (void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
276df8bdeb3Sjohnz
277df8bdeb3Sjohnz if (!elfcertlib_init(ess)) {
278df8bdeb3Sjohnz cryptodebug("elfsign_begin: failed initialization");
279df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
280df8bdeb3Sjohnz }
281df8bdeb3Sjohnz
282df8bdeb3Sjohnz ess->es_elf = NULL;
283df8bdeb3Sjohnz ess->es_action = action;
284df8bdeb3Sjohnz ess->es_version = FILESIG_UNKNOWN;
285df8bdeb3Sjohnz ess->es_pathname = NULL;
286df8bdeb3Sjohnz ess->es_certpath = NULL;
287df8bdeb3Sjohnz
288df8bdeb3Sjohnz if (filename == NULL) {
289df8bdeb3Sjohnz *essp = ess;
290df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
291df8bdeb3Sjohnz }
292df8bdeb3Sjohnz
293df8bdeb3Sjohnz if ((ess->es_fd = open(filename, oflags)) == -1) {
294df8bdeb3Sjohnz elfsign_end(ess);
295df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
296df8bdeb3Sjohnz }
297df8bdeb3Sjohnz if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
298df8bdeb3Sjohnz elfsign_end(ess);
299df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
300df8bdeb3Sjohnz }
301df8bdeb3Sjohnz if ((ess->es_pathname = strdup(filename)) == NULL) {
302df8bdeb3Sjohnz elfsign_end(ess);
303df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
304df8bdeb3Sjohnz }
305df8bdeb3Sjohnz /*
306df8bdeb3Sjohnz * The following lock is released in elfsign_end() when we close(2)
307df8bdeb3Sjohnz * the es_fd. This ensures that we aren't trying verify a file
308df8bdeb3Sjohnz * we are currently updating.
309df8bdeb3Sjohnz */
310df8bdeb3Sjohnz ess->es_flock.l_type = l_type;
311df8bdeb3Sjohnz ess->es_flock.l_whence = SEEK_CUR;
312df8bdeb3Sjohnz ess->es_flock.l_start = 0;
313df8bdeb3Sjohnz ess->es_flock.l_len = 0;
314df8bdeb3Sjohnz if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
315df8bdeb3Sjohnz cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
316df8bdeb3Sjohnz ess->es_pathname, strerror(errno));
317df8bdeb3Sjohnz elfsign_end(ess);
318df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
319df8bdeb3Sjohnz }
320df8bdeb3Sjohnz
321df8bdeb3Sjohnz if (elf_version(EV_CURRENT) == EV_NONE) {
322df8bdeb3Sjohnz elfsign_end(ess);
323df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
324df8bdeb3Sjohnz }
325df8bdeb3Sjohnz
326df8bdeb3Sjohnz if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
327df8bdeb3Sjohnz (Elf *)NULL)) == NULL) {
328df8bdeb3Sjohnz cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
329df8bdeb3Sjohnz elfsign_end(ess);
330df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
331df8bdeb3Sjohnz }
332df8bdeb3Sjohnz
333df8bdeb3Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
334df8bdeb3Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
335df8bdeb3Sjohnz elfsign_end(ess);
336df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
337df8bdeb3Sjohnz }
338df8bdeb3Sjohnz ess->es_has_phdr = (elfehdr.e_phnum != 0);
339df8bdeb3Sjohnz
340df8bdeb3Sjohnz uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
341df8bdeb3Sjohnz ident = elf_getident(ess->es_elf, NULL);
342df8bdeb3Sjohnz if (ident == NULL) {
343df8bdeb3Sjohnz cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
344df8bdeb3Sjohnz elfsign_end(ess);
345df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
346df8bdeb3Sjohnz }
347df8bdeb3Sjohnz ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
348df8bdeb3Sjohnz ess->es_ei_class = ident[EI_CLASS];
349df8bdeb3Sjohnz
350df8bdeb3Sjohnz /*
351df8bdeb3Sjohnz * Call elf_getshstrndx to be sure we have a real ELF object
352df8bdeb3Sjohnz * this is required because elf_begin doesn't check that.
353df8bdeb3Sjohnz */
3545c017525SAli Bahrami if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
355df8bdeb3Sjohnz elfsign_end(ess);
356df8bdeb3Sjohnz cryptodebug("elfsign_begin: elf_getshstrndx failed");
357df8bdeb3Sjohnz return (ELFSIGN_INVALID_ELFOBJ);
358df8bdeb3Sjohnz }
359df8bdeb3Sjohnz
360df8bdeb3Sjohnz /*
361df8bdeb3Sjohnz * Make sure libelf doesn't rearrange section ordering / offsets.
362df8bdeb3Sjohnz */
363df8bdeb3Sjohnz (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
364df8bdeb3Sjohnz
365df8bdeb3Sjohnz *essp = ess;
366df8bdeb3Sjohnz
367df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
368df8bdeb3Sjohnz }
369df8bdeb3Sjohnz
370df8bdeb3Sjohnz /*
371df8bdeb3Sjohnz * elfsign_end - cleanup the ELFsign_t
372df8bdeb3Sjohnz *
373df8bdeb3Sjohnz * IN/OUT: ess
374df8bdeb3Sjohnz */
375df8bdeb3Sjohnz void
elfsign_end(ELFsign_t ess)376df8bdeb3Sjohnz elfsign_end(ELFsign_t ess)
377df8bdeb3Sjohnz {
378df8bdeb3Sjohnz if (ess == NULL)
379df8bdeb3Sjohnz return;
380df8bdeb3Sjohnz
381df8bdeb3Sjohnz if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
382df8bdeb3Sjohnz if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
383df8bdeb3Sjohnz cryptodebug("elf_update() failed: %s",
384df8bdeb3Sjohnz elf_errmsg(-1));
385df8bdeb3Sjohnz return;
386df8bdeb3Sjohnz }
387df8bdeb3Sjohnz }
388df8bdeb3Sjohnz
389df8bdeb3Sjohnz if (ess->es_fd != -1) {
390df8bdeb3Sjohnz (void) close(ess->es_fd);
391df8bdeb3Sjohnz ess->es_fd = -1;
392df8bdeb3Sjohnz }
393df8bdeb3Sjohnz
394df8bdeb3Sjohnz if (ess->es_pathname != NULL) {
395df8bdeb3Sjohnz free(ess->es_pathname);
396df8bdeb3Sjohnz ess->es_pathname = NULL;
397df8bdeb3Sjohnz }
398df8bdeb3Sjohnz if (ess->es_certpath != NULL) {
399df8bdeb3Sjohnz free(ess->es_certpath);
400df8bdeb3Sjohnz ess->es_certpath = NULL;
401df8bdeb3Sjohnz }
402df8bdeb3Sjohnz
403df8bdeb3Sjohnz if (ess->es_elf != NULL) {
404df8bdeb3Sjohnz (void) elf_end(ess->es_elf);
405df8bdeb3Sjohnz ess->es_elf = NULL;
406df8bdeb3Sjohnz }
407df8bdeb3Sjohnz
408df8bdeb3Sjohnz elfcertlib_fini(ess);
409df8bdeb3Sjohnz
410df8bdeb3Sjohnz free(ess);
411df8bdeb3Sjohnz }
412df8bdeb3Sjohnz
413df8bdeb3Sjohnz /*
414df8bdeb3Sjohnz * set the certificate path
415df8bdeb3Sjohnz */
416df8bdeb3Sjohnz ELFsign_status_t
elfsign_setcertpath(ELFsign_t ess,const char * certpath)417df8bdeb3Sjohnz elfsign_setcertpath(ELFsign_t ess, const char *certpath)
418df8bdeb3Sjohnz {
419df8bdeb3Sjohnz /*
420df8bdeb3Sjohnz * Normally use of access(2) is insecure, here we are only
421df8bdeb3Sjohnz * doing it to help provide early failure and better error
422df8bdeb3Sjohnz * checking, so there is no race condition.
423df8bdeb3Sjohnz */
4243b0164d5Sjohnz if (access(certpath, R_OK) != 0)
425df8bdeb3Sjohnz return (ELFSIGN_INVALID_CERTPATH);
4263b0164d5Sjohnz
4273b0164d5Sjohnz if ((ess->es_certpath = strdup(certpath)) == NULL)
4283b0164d5Sjohnz return (ELFSIGN_FAILED);
429df8bdeb3Sjohnz
430df8bdeb3Sjohnz if (ES_ACTISUPDATE(ess->es_action)) {
431df8bdeb3Sjohnz ELFCert_t cert = NULL;
432df8bdeb3Sjohnz char *subject;
433df8bdeb3Sjohnz
434df8bdeb3Sjohnz /* set the version based on the certificate */
435df8bdeb3Sjohnz if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
436df8bdeb3Sjohnz &cert, ess->es_action)) {
437df8bdeb3Sjohnz if ((subject = elfcertlib_getdn(cert)) != NULL) {
438df8bdeb3Sjohnz if (strstr(subject, ELFSIGN_CRYPTO))
439df8bdeb3Sjohnz ess->es_version = (ess->es_action ==
440df8bdeb3Sjohnz ES_UPDATE_RSA_MD5_SHA1) ?
441df8bdeb3Sjohnz FILESIG_VERSION1 : FILESIG_VERSION3;
442df8bdeb3Sjohnz else
443df8bdeb3Sjohnz ess->es_version = (ess->es_action ==
444df8bdeb3Sjohnz ES_UPDATE_RSA_MD5_SHA1) ?
445df8bdeb3Sjohnz FILESIG_VERSION2 : FILESIG_VERSION4;
446df8bdeb3Sjohnz }
447df8bdeb3Sjohnz elfcertlib_releasecert(ess, cert);
448df8bdeb3Sjohnz }
449df8bdeb3Sjohnz if (ess->es_version == FILESIG_UNKNOWN)
450df8bdeb3Sjohnz return (ELFSIGN_FAILED);
451df8bdeb3Sjohnz }
452df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
453df8bdeb3Sjohnz }
454df8bdeb3Sjohnz
455df8bdeb3Sjohnz /*
456df8bdeb3Sjohnz * set the callback context
457df8bdeb3Sjohnz */
458df8bdeb3Sjohnz void
elfsign_setcallbackctx(ELFsign_t ess,void * ctx)459df8bdeb3Sjohnz elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
460df8bdeb3Sjohnz {
461df8bdeb3Sjohnz ess->es_callbackctx = ctx;
462df8bdeb3Sjohnz }
463df8bdeb3Sjohnz
464df8bdeb3Sjohnz /*
465df8bdeb3Sjohnz * set the signature extraction callback
466df8bdeb3Sjohnz */
467df8bdeb3Sjohnz void
elfsign_setsigvercallback(ELFsign_t ess,void (* cb)(void *,void *,size_t,ELFCert_t))468df8bdeb3Sjohnz elfsign_setsigvercallback(ELFsign_t ess,
469df8bdeb3Sjohnz void (*cb)(void *, void *, size_t, ELFCert_t))
470df8bdeb3Sjohnz {
471df8bdeb3Sjohnz ess->es_sigvercallback = cb;
472df8bdeb3Sjohnz }
473df8bdeb3Sjohnz
474df8bdeb3Sjohnz /*
475df8bdeb3Sjohnz * elfsign_signatures
476df8bdeb3Sjohnz *
477df8bdeb3Sjohnz * IN: ess, fsspp, action
478df8bdeb3Sjohnz * OUT: fsspp
479df8bdeb3Sjohnz */
480df8bdeb3Sjohnz ELFsign_status_t
elfsign_signatures(ELFsign_t ess,struct filesignatures ** fsspp,size_t * fslen,enum ES_ACTION action)481df8bdeb3Sjohnz elfsign_signatures(ELFsign_t ess,
482df8bdeb3Sjohnz struct filesignatures **fsspp,
483df8bdeb3Sjohnz size_t *fslen,
484df8bdeb3Sjohnz enum ES_ACTION action)
485df8bdeb3Sjohnz {
486df8bdeb3Sjohnz Elf_Scn *scn = NULL, *sig_scn = NULL;
487df8bdeb3Sjohnz GElf_Shdr shdr;
488df8bdeb3Sjohnz Elf_Data *data = NULL;
489df8bdeb3Sjohnz const char *elf_section = SUNW_ELF_SIGNATURE_ID;
490df8bdeb3Sjohnz int fscnt, fssize;
491df8bdeb3Sjohnz struct filesig *fsgp, *fsgpnext;
492df8bdeb3Sjohnz uint64_t sig_offset = 0;
493df8bdeb3Sjohnz
494df8bdeb3Sjohnz cryptodebug("elfsign_signature");
495df8bdeb3Sjohnz if ((ess == NULL) || (fsspp == NULL)) {
496df8bdeb3Sjohnz cryptodebug("invalid arguments");
497df8bdeb3Sjohnz return (ELFSIGN_UNKNOWN);
498df8bdeb3Sjohnz }
499df8bdeb3Sjohnz
500df8bdeb3Sjohnz cryptodebug("elfsign_signature %s for %s",
501df8bdeb3Sjohnz ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
502df8bdeb3Sjohnz
503df8bdeb3Sjohnz (void) elf_errno();
504df8bdeb3Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
505df8bdeb3Sjohnz const char *sh_name;
506df8bdeb3Sjohnz /*
507df8bdeb3Sjohnz * Do a string compare to examine each section header
508df8bdeb3Sjohnz * to see if this is the section that needs to be updated.
509df8bdeb3Sjohnz */
510df8bdeb3Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) {
511df8bdeb3Sjohnz cryptodebug("gelf_getshdr() failed: %s",
512df8bdeb3Sjohnz elf_errmsg(-1));
513df8bdeb3Sjohnz return (ELFSIGN_FAILED);
514df8bdeb3Sjohnz }
515df8bdeb3Sjohnz sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
516df8bdeb3Sjohnz (size_t)shdr.sh_name);
517df8bdeb3Sjohnz if (strcmp(sh_name, elf_section) == 0) {
518df8bdeb3Sjohnz cryptodebug("elfsign_signature: found %s", elf_section);
519df8bdeb3Sjohnz sig_scn = scn;
520df8bdeb3Sjohnz break;
521df8bdeb3Sjohnz }
522df8bdeb3Sjohnz if (shdr.sh_type != SHT_NOBITS &&
523df8bdeb3Sjohnz sig_offset < shdr.sh_offset + shdr.sh_size) {
524df8bdeb3Sjohnz sig_offset = shdr.sh_offset + shdr.sh_size;
525df8bdeb3Sjohnz }
526df8bdeb3Sjohnz }
527df8bdeb3Sjohnz if (elf_errmsg(0) != NULL) {
528df8bdeb3Sjohnz cryptodebug("unexpected error: %s", elf_section,
529df8bdeb3Sjohnz elf_errmsg(-1));
530df8bdeb3Sjohnz return (ELFSIGN_FAILED);
531df8bdeb3Sjohnz }
532df8bdeb3Sjohnz
533df8bdeb3Sjohnz if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) {
534df8bdeb3Sjohnz size_t old_size, new_size;
535df8bdeb3Sjohnz char *new_d_buf;
536df8bdeb3Sjohnz
537df8bdeb3Sjohnz cryptodebug("elfsign_signature: %s not found - creating",
538df8bdeb3Sjohnz elf_section);
539df8bdeb3Sjohnz
540df8bdeb3Sjohnz /*
541df8bdeb3Sjohnz * insert section name in .shstrtab
542df8bdeb3Sjohnz */
543df8bdeb3Sjohnz if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
544df8bdeb3Sjohnz cryptodebug("elf_getscn() failed: %s",
545df8bdeb3Sjohnz elf_errmsg(-1));
546df8bdeb3Sjohnz return (ELFSIGN_FAILED);
547df8bdeb3Sjohnz }
548df8bdeb3Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) {
549df8bdeb3Sjohnz cryptodebug("gelf_getshdr() failed: %s",
550df8bdeb3Sjohnz elf_errmsg(-1));
551df8bdeb3Sjohnz return (ELFSIGN_FAILED);
552df8bdeb3Sjohnz }
553df8bdeb3Sjohnz if ((data = elf_getdata(scn, data)) == NULL) {
554df8bdeb3Sjohnz cryptodebug("elf_getdata() failed: %s",
555df8bdeb3Sjohnz elf_errmsg(-1));
556df8bdeb3Sjohnz return (ELFSIGN_FAILED);
557df8bdeb3Sjohnz }
558df8bdeb3Sjohnz old_size = data->d_size;
559df8bdeb3Sjohnz if (old_size != shdr.sh_size) {
560df8bdeb3Sjohnz cryptodebug("mismatch between data size %d "
561df8bdeb3Sjohnz "and section size %lld", old_size, shdr.sh_size);
562df8bdeb3Sjohnz return (ELFSIGN_FAILED);
563df8bdeb3Sjohnz }
564df8bdeb3Sjohnz new_size = old_size + strlen(elf_section) + 1;
565df8bdeb3Sjohnz if ((new_d_buf = malloc(new_size)) == NULL)
566df8bdeb3Sjohnz return (ELFSIGN_FAILED);
567df8bdeb3Sjohnz
568df8bdeb3Sjohnz (void) memcpy(new_d_buf, data->d_buf, old_size);
569df8bdeb3Sjohnz (void) strlcpy(new_d_buf + old_size, elf_section,
570df8bdeb3Sjohnz new_size - old_size);
571df8bdeb3Sjohnz data->d_buf = new_d_buf;
572df8bdeb3Sjohnz data->d_size = new_size;
573df8bdeb3Sjohnz data->d_align = 1;
574df8bdeb3Sjohnz /*
575df8bdeb3Sjohnz * Add the section name passed in to the end of the file.
576df8bdeb3Sjohnz * Initialize the fields in the Section Header that
577df8bdeb3Sjohnz * libelf will not fill in.
578df8bdeb3Sjohnz */
579df8bdeb3Sjohnz if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
580df8bdeb3Sjohnz cryptodebug("elf_newscn() failed: %s",
581df8bdeb3Sjohnz elf_errmsg(-1));
582df8bdeb3Sjohnz return (ELFSIGN_FAILED);
583df8bdeb3Sjohnz }
584df8bdeb3Sjohnz if (gelf_getshdr(sig_scn, &shdr) == 0) {
585df8bdeb3Sjohnz cryptodebug("gelf_getshdr() failed: %s",
586df8bdeb3Sjohnz elf_errmsg(-1));
587df8bdeb3Sjohnz return (ELFSIGN_FAILED);
588df8bdeb3Sjohnz }
589df8bdeb3Sjohnz shdr.sh_name = old_size;
590df8bdeb3Sjohnz shdr.sh_type = SHT_SUNW_SIGNATURE;
591df8bdeb3Sjohnz shdr.sh_flags = SHF_EXCLUDE;
592df8bdeb3Sjohnz shdr.sh_addr = 0;
593df8bdeb3Sjohnz shdr.sh_link = 0;
594df8bdeb3Sjohnz shdr.sh_info = 0;
595df8bdeb3Sjohnz shdr.sh_size = 0;
596df8bdeb3Sjohnz shdr.sh_offset = sig_offset;
597df8bdeb3Sjohnz shdr.sh_addralign = 1;
598df8bdeb3Sjohnz
599df8bdeb3Sjohnz /*
600df8bdeb3Sjohnz * Flush the changes to the underlying elf32 or elf64
601df8bdeb3Sjohnz * section header.
602df8bdeb3Sjohnz */
603df8bdeb3Sjohnz if (gelf_update_shdr(sig_scn, &shdr) == 0) {
604df8bdeb3Sjohnz cryptodebug("gelf_update_shdr failed");
605df8bdeb3Sjohnz return (ELFSIGN_FAILED);
606df8bdeb3Sjohnz }
607df8bdeb3Sjohnz
608df8bdeb3Sjohnz if ((data = elf_newdata(sig_scn)) == NULL) {
609df8bdeb3Sjohnz cryptodebug("can't add elf data area for %s: %s",
610df8bdeb3Sjohnz elf_section, elf_errmsg(-1));
611df8bdeb3Sjohnz return (ELFSIGN_FAILED);
612df8bdeb3Sjohnz }
613df8bdeb3Sjohnz if (elfsign_adjustoffsets(ess, scn,
614df8bdeb3Sjohnz old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
615df8bdeb3Sjohnz cryptodebug("can't adjust for new section name %s",
616df8bdeb3Sjohnz elf_section);
617df8bdeb3Sjohnz return (ELFSIGN_FAILED);
618df8bdeb3Sjohnz }
619df8bdeb3Sjohnz } else {
620df8bdeb3Sjohnz if (sig_scn == NULL) {
621df8bdeb3Sjohnz cryptodebug("can't find signature section");
622df8bdeb3Sjohnz *fsspp = NULL;
623df8bdeb3Sjohnz return (ELFSIGN_NOTSIGNED);
624df8bdeb3Sjohnz }
625df8bdeb3Sjohnz if ((data = elf_getdata(sig_scn, NULL)) == 0) {
626df8bdeb3Sjohnz cryptodebug("can't get section data for %s",
627df8bdeb3Sjohnz elf_section);
628df8bdeb3Sjohnz return (ELFSIGN_FAILED);
629df8bdeb3Sjohnz }
630df8bdeb3Sjohnz }
631df8bdeb3Sjohnz
632df8bdeb3Sjohnz if (ES_ACTISUPDATE(action)) {
633df8bdeb3Sjohnz fssize = offsetof(struct filesignatures, _u1);
634df8bdeb3Sjohnz if (*fsspp != NULL) {
635df8bdeb3Sjohnz fsgp = &(*fsspp)->filesig_sig;
636df8bdeb3Sjohnz for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
637df8bdeb3Sjohnz fscnt++) {
638df8bdeb3Sjohnz fsgpnext = filesig_next(fsgp);
639df8bdeb3Sjohnz fssize += (char *)(fsgpnext) - (char *)(fsgp);
640df8bdeb3Sjohnz fsgp = fsgpnext;
641df8bdeb3Sjohnz }
642df8bdeb3Sjohnz }
643df8bdeb3Sjohnz if (shdr.sh_addr != 0) {
644df8bdeb3Sjohnz cryptodebug("section %s is part of a loadable segment, "
645df8bdeb3Sjohnz "it cannot be changed.\n", elf_section);
646df8bdeb3Sjohnz return (ELFSIGN_FAILED);
647df8bdeb3Sjohnz }
648df8bdeb3Sjohnz if ((data->d_buf = malloc(fssize)) == NULL)
649df8bdeb3Sjohnz return (ELFSIGN_FAILED);
650df8bdeb3Sjohnz if (*fsspp != NULL) {
651df8bdeb3Sjohnz (void) memcpy(data->d_buf, *fsspp, fssize);
652df8bdeb3Sjohnz (void) elfsign_switch(ess,
653df8bdeb3Sjohnz (struct filesignatures *)data->d_buf, action);
654df8bdeb3Sjohnz }
655df8bdeb3Sjohnz data->d_size = fssize;
656df8bdeb3Sjohnz data->d_align = 1;
657df8bdeb3Sjohnz data->d_type = ELF_T_BYTE;
658df8bdeb3Sjohnz cryptodebug("elfsign_signature: data->d_size = %d",
659df8bdeb3Sjohnz data->d_size);
660df8bdeb3Sjohnz if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
661df8bdeb3Sjohnz ELFSIGN_SUCCESS) {
662df8bdeb3Sjohnz cryptodebug("can't adjust for revised signature "
663df8bdeb3Sjohnz "section contents");
664df8bdeb3Sjohnz return (ELFSIGN_FAILED);
665df8bdeb3Sjohnz }
666df8bdeb3Sjohnz } else {
667df8bdeb3Sjohnz *fsspp = malloc(data->d_size);
668df8bdeb3Sjohnz if (*fsspp == NULL)
669df8bdeb3Sjohnz return (ELFSIGN_FAILED);
670df8bdeb3Sjohnz (void) memcpy(*fsspp, data->d_buf, data->d_size);
671df8bdeb3Sjohnz if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
672df8bdeb3Sjohnz free(*fsspp);
673df8bdeb3Sjohnz *fsspp = NULL;
674df8bdeb3Sjohnz return (ELFSIGN_FAILED);
675df8bdeb3Sjohnz }
676df8bdeb3Sjohnz *fslen = data->d_size;
677df8bdeb3Sjohnz }
678df8bdeb3Sjohnz
679df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
680df8bdeb3Sjohnz }
681df8bdeb3Sjohnz
682df8bdeb3Sjohnz static ELFsign_status_t
elfsign_adjustoffsets(ELFsign_t ess,Elf_Scn * scn,uint64_t new_size)683df8bdeb3Sjohnz elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
684df8bdeb3Sjohnz {
685df8bdeb3Sjohnz GElf_Ehdr elfehdr;
686df8bdeb3Sjohnz GElf_Shdr shdr;
687df8bdeb3Sjohnz uint64_t prev_end, scn_offset;
688df8bdeb3Sjohnz char *name;
689df8bdeb3Sjohnz Elf_Scn *scnp;
690df8bdeb3Sjohnz Elf_Data *data;
691df8bdeb3Sjohnz ELFsign_status_t retval = ELFSIGN_FAILED;
692df8bdeb3Sjohnz struct scninfo {
693df8bdeb3Sjohnz struct scninfo *scni_next;
694df8bdeb3Sjohnz Elf_Scn *scni_scn;
695df8bdeb3Sjohnz uint64_t scni_offset;
696df8bdeb3Sjohnz } *scnip = NULL, *tmpscnip, **scnipp;
697df8bdeb3Sjohnz
698df8bdeb3Sjohnz /* get the size of the current section */
699df8bdeb3Sjohnz if (gelf_getshdr(scn, &shdr) == NULL)
700df8bdeb3Sjohnz return (ELFSIGN_FAILED);
701df8bdeb3Sjohnz if (shdr.sh_size == new_size)
702df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
703df8bdeb3Sjohnz scn_offset = shdr.sh_offset;
704df8bdeb3Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx,
705df8bdeb3Sjohnz (size_t)shdr.sh_name);
706df8bdeb3Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
707df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
708df8bdeb3Sjohnz "can't move allocated section %s", name ? name : "NULL");
709df8bdeb3Sjohnz return (ELFSIGN_FAILED);
710df8bdeb3Sjohnz }
711df8bdeb3Sjohnz
712df8bdeb3Sjohnz /* resize the desired section */
713df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
714df8bdeb3Sjohnz "resizing %s at 0x%llx from 0x%llx to 0x%llx",
715df8bdeb3Sjohnz name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
716df8bdeb3Sjohnz shdr.sh_size = new_size;
717df8bdeb3Sjohnz if (gelf_update_shdr(scn, &shdr) == 0) {
718df8bdeb3Sjohnz cryptodebug("gelf_update_shdr failed");
719df8bdeb3Sjohnz goto bad;
720df8bdeb3Sjohnz }
721df8bdeb3Sjohnz prev_end = shdr.sh_offset + shdr.sh_size;
722df8bdeb3Sjohnz
723df8bdeb3Sjohnz /*
724df8bdeb3Sjohnz * find sections whose data follows the changed section
725df8bdeb3Sjohnz * must scan all sections since section data may not
726df8bdeb3Sjohnz * be in same order as section headers
727df8bdeb3Sjohnz */
728df8bdeb3Sjohnz scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */
729df8bdeb3Sjohnz while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
730df8bdeb3Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL)
731df8bdeb3Sjohnz goto bad;
732df8bdeb3Sjohnz if (shdr.sh_offset <= scn_offset)
733df8bdeb3Sjohnz continue;
734df8bdeb3Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx,
735df8bdeb3Sjohnz (size_t)shdr.sh_name);
736df8bdeb3Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
737df8bdeb3Sjohnz if (shdr.sh_type == SHT_NOBITS) {
738df8bdeb3Sjohnz /* .bss can occasionally overlap .shrtab */
739df8bdeb3Sjohnz continue;
740df8bdeb3Sjohnz }
741df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
742df8bdeb3Sjohnz "can't move allocated section %s",
743df8bdeb3Sjohnz name ? name : "NULL");
744df8bdeb3Sjohnz goto bad;
745df8bdeb3Sjohnz }
746df8bdeb3Sjohnz /*
747df8bdeb3Sjohnz * force reading of data to memory image
748df8bdeb3Sjohnz */
749df8bdeb3Sjohnz data = NULL;
750df8bdeb3Sjohnz while ((data = elf_rawdata(scnp, data)) != NULL)
751df8bdeb3Sjohnz ;
752df8bdeb3Sjohnz /*
753df8bdeb3Sjohnz * capture section information
754df8bdeb3Sjohnz * insert into list in order of sh_offset
755df8bdeb3Sjohnz */
756df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
757df8bdeb3Sjohnz "may have to adjust section %s, offset 0x%llx",
758df8bdeb3Sjohnz name ? name : "NULL", shdr.sh_offset);
759df8bdeb3Sjohnz tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
760df8bdeb3Sjohnz if (tmpscnip == NULL) {
761df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
762df8bdeb3Sjohnz "memory allocation failure");
763df8bdeb3Sjohnz goto bad;
764df8bdeb3Sjohnz }
765df8bdeb3Sjohnz tmpscnip->scni_scn = scnp;
766df8bdeb3Sjohnz tmpscnip->scni_offset = shdr.sh_offset;
767df8bdeb3Sjohnz for (scnipp = &scnip; *scnipp != NULL;
768df8bdeb3Sjohnz scnipp = &(*scnipp)->scni_next) {
769df8bdeb3Sjohnz if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
770df8bdeb3Sjohnz break;
771df8bdeb3Sjohnz }
772df8bdeb3Sjohnz tmpscnip->scni_next = *scnipp;
773df8bdeb3Sjohnz *scnipp = tmpscnip;
774df8bdeb3Sjohnz }
775df8bdeb3Sjohnz
776df8bdeb3Sjohnz /* move following sections as necessary */
777df8bdeb3Sjohnz for (tmpscnip = scnip; tmpscnip != NULL;
778df8bdeb3Sjohnz tmpscnip = tmpscnip->scni_next) {
779df8bdeb3Sjohnz scnp = tmpscnip->scni_scn;
780df8bdeb3Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL) {
781df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
782df8bdeb3Sjohnz "elf_getshdr for section %d failed",
783df8bdeb3Sjohnz elf_ndxscn(scnp));
784df8bdeb3Sjohnz goto bad;
785df8bdeb3Sjohnz }
786df8bdeb3Sjohnz if (shdr.sh_offset >= prev_end)
787df8bdeb3Sjohnz break;
788df8bdeb3Sjohnz prev_end = (prev_end + shdr.sh_addralign - 1) &
789df8bdeb3Sjohnz (-shdr.sh_addralign);
790df8bdeb3Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx,
791df8bdeb3Sjohnz (size_t)shdr.sh_name);
792df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
793df8bdeb3Sjohnz "moving %s size 0x%llx from 0x%llx to 0x%llx",
794df8bdeb3Sjohnz name ? name : "NULL", shdr.sh_size,
795df8bdeb3Sjohnz shdr.sh_offset, prev_end);
796df8bdeb3Sjohnz shdr.sh_offset = prev_end;
797df8bdeb3Sjohnz if (gelf_update_shdr(scnp, &shdr) == 0) {
798df8bdeb3Sjohnz cryptodebug("gelf_update_shdr failed");
799df8bdeb3Sjohnz goto bad;
800df8bdeb3Sjohnz }
801df8bdeb3Sjohnz prev_end = shdr.sh_offset + shdr.sh_size;
802df8bdeb3Sjohnz }
803df8bdeb3Sjohnz
804df8bdeb3Sjohnz /*
805df8bdeb3Sjohnz * adjust section header offset in elf header
806df8bdeb3Sjohnz */
807df8bdeb3Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
808df8bdeb3Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
809df8bdeb3Sjohnz goto bad;
810df8bdeb3Sjohnz }
811df8bdeb3Sjohnz if (elfehdr.e_shoff < prev_end) {
812df8bdeb3Sjohnz if (ess->es_ei_class == ELFCLASS32)
813df8bdeb3Sjohnz prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
814df8bdeb3Sjohnz (-ELF32_FSZ_OFF);
815df8bdeb3Sjohnz else if (ess->es_ei_class == ELFCLASS64)
816df8bdeb3Sjohnz prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
817df8bdeb3Sjohnz (-ELF64_FSZ_OFF);
818df8bdeb3Sjohnz cryptodebug("elfsign_adjustoffsets: "
819df8bdeb3Sjohnz "move sh_off from 0x%llx to 0x%llx",
820df8bdeb3Sjohnz elfehdr.e_shoff, prev_end);
821df8bdeb3Sjohnz elfehdr.e_shoff = prev_end;
822df8bdeb3Sjohnz if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
823df8bdeb3Sjohnz cryptodebug("elf_update_ehdr() failed: %s",
824df8bdeb3Sjohnz elf_errmsg(-1));
825df8bdeb3Sjohnz goto bad;
826df8bdeb3Sjohnz }
827df8bdeb3Sjohnz }
828df8bdeb3Sjohnz
829df8bdeb3Sjohnz retval = ELFSIGN_SUCCESS;
830df8bdeb3Sjohnz
831df8bdeb3Sjohnz bad:
832df8bdeb3Sjohnz while (scnip != NULL) {
833df8bdeb3Sjohnz tmpscnip = scnip->scni_next;
834df8bdeb3Sjohnz free(scnip);
835df8bdeb3Sjohnz scnip = tmpscnip;
836df8bdeb3Sjohnz }
837df8bdeb3Sjohnz return (retval);
838df8bdeb3Sjohnz }
839df8bdeb3Sjohnz
840df8bdeb3Sjohnz struct filesignatures *
elfsign_insert_dso(ELFsign_t ess,struct filesignatures * fssp,const char * dn,int dn_len,const uchar_t * sig,int sig_len,const char * oid,int oid_len)841df8bdeb3Sjohnz elfsign_insert_dso(ELFsign_t ess,
842df8bdeb3Sjohnz struct filesignatures *fssp,
843df8bdeb3Sjohnz const char *dn,
844df8bdeb3Sjohnz int dn_len,
845df8bdeb3Sjohnz const uchar_t *sig,
846df8bdeb3Sjohnz int sig_len,
847df8bdeb3Sjohnz const char *oid,
848df8bdeb3Sjohnz int oid_len)
849df8bdeb3Sjohnz {
850df8bdeb3Sjohnz return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
851df8bdeb3Sjohnz sig, sig_len, oid, oid_len));
852df8bdeb3Sjohnz }
853df8bdeb3Sjohnz
854df8bdeb3Sjohnz /*ARGSUSED*/
855df8bdeb3Sjohnz filesig_vers_t
elfsign_extract_sig(ELFsign_t ess,struct filesignatures * fssp,uchar_t * sig,size_t * sig_len)856df8bdeb3Sjohnz elfsign_extract_sig(ELFsign_t ess,
857df8bdeb3Sjohnz struct filesignatures *fssp,
858df8bdeb3Sjohnz uchar_t *sig,
859df8bdeb3Sjohnz size_t *sig_len)
860df8bdeb3Sjohnz {
861df8bdeb3Sjohnz struct filesig_extraction fsx;
862df8bdeb3Sjohnz filesig_vers_t version;
863df8bdeb3Sjohnz
864df8bdeb3Sjohnz if (fssp == NULL)
865df8bdeb3Sjohnz return (FILESIG_UNKNOWN);
866df8bdeb3Sjohnz if (fssp->filesig_cnt != 1)
867df8bdeb3Sjohnz return (FILESIG_UNKNOWN);
868df8bdeb3Sjohnz version = filesig_extract(&fssp->filesig_sig, &fsx);
869df8bdeb3Sjohnz switch (version) {
870df8bdeb3Sjohnz case FILESIG_VERSION1:
871df8bdeb3Sjohnz case FILESIG_VERSION2:
872df8bdeb3Sjohnz case FILESIG_VERSION3:
873df8bdeb3Sjohnz case FILESIG_VERSION4:
874df8bdeb3Sjohnz if (*sig_len >= fsx.fsx_sig_len) {
875df8bdeb3Sjohnz (void) memcpy((char *)sig, (char *)fsx.fsx_signature,
876df8bdeb3Sjohnz *sig_len);
877df8bdeb3Sjohnz *sig_len = fsx.fsx_sig_len;
878df8bdeb3Sjohnz } else
879df8bdeb3Sjohnz version = FILESIG_UNKNOWN;
880df8bdeb3Sjohnz break;
881df8bdeb3Sjohnz default:
882df8bdeb3Sjohnz version = FILESIG_UNKNOWN;
883df8bdeb3Sjohnz break;
884df8bdeb3Sjohnz }
885df8bdeb3Sjohnz
886df8bdeb3Sjohnz if (ess->es_version == FILESIG_UNKNOWN) {
887df8bdeb3Sjohnz ess->es_version = version;
888df8bdeb3Sjohnz }
889df8bdeb3Sjohnz
890df8bdeb3Sjohnz return (version);
891df8bdeb3Sjohnz }
892df8bdeb3Sjohnz
893df8bdeb3Sjohnz static ELFsign_status_t
elfsign_hash_common(ELFsign_t ess,uchar_t * hash,size_t * hash_len,boolean_t hash_mem_resident)894df8bdeb3Sjohnz elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
895df8bdeb3Sjohnz boolean_t hash_mem_resident)
896df8bdeb3Sjohnz {
897df8bdeb3Sjohnz Elf_Scn *scn = NULL;
898df8bdeb3Sjohnz ELFsign_status_t elfstat;
899df8bdeb3Sjohnz GElf_Shdr shdr;
900df8bdeb3Sjohnz SHA1_CTX ctx;
901df8bdeb3Sjohnz
902df8bdeb3Sjohnz /* The buffer must be large enough to hold the hash */
903df8bdeb3Sjohnz if (*hash_len < SHA1_DIGEST_LENGTH)
904df8bdeb3Sjohnz return (ELFSIGN_FAILED);
905df8bdeb3Sjohnz
906df8bdeb3Sjohnz bzero(hash, *hash_len);
907df8bdeb3Sjohnz
908df8bdeb3Sjohnz /* Initialize the digest session */
909df8bdeb3Sjohnz SHA1Init(&ctx);
910df8bdeb3Sjohnz
911df8bdeb3Sjohnz scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */
912df8bdeb3Sjohnz (void) elf_errno();
913df8bdeb3Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
914df8bdeb3Sjohnz char *name = NULL;
915df8bdeb3Sjohnz Elf_Data *data = NULL;
916df8bdeb3Sjohnz
917df8bdeb3Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) {
918df8bdeb3Sjohnz elfstat = ELFSIGN_FAILED;
919df8bdeb3Sjohnz goto done;
920df8bdeb3Sjohnz }
921df8bdeb3Sjohnz
922df8bdeb3Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx,
923df8bdeb3Sjohnz (size_t)shdr.sh_name);
924df8bdeb3Sjohnz if (name == NULL)
925df8bdeb3Sjohnz name = "NULL";
926df8bdeb3Sjohnz
927df8bdeb3Sjohnz if (!hash_mem_resident &&
928df8bdeb3Sjohnz (ess->es_version == FILESIG_VERSION1 ||
929df8bdeb3Sjohnz ess->es_version == FILESIG_VERSION3)) {
930df8bdeb3Sjohnz /*
931df8bdeb3Sjohnz * skip the signature section only
932df8bdeb3Sjohnz */
933df8bdeb3Sjohnz if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
934df8bdeb3Sjohnz cryptodebug("elfsign_hash: skipping %s", name);
935df8bdeb3Sjohnz continue;
936df8bdeb3Sjohnz }
937df8bdeb3Sjohnz } else if (!(shdr.sh_flags & SHF_ALLOC)) {
938df8bdeb3Sjohnz /*
939df8bdeb3Sjohnz * select only memory resident sections
940df8bdeb3Sjohnz */
941df8bdeb3Sjohnz cryptodebug("elfsign_hash: skipping %s", name);
942df8bdeb3Sjohnz continue;
943df8bdeb3Sjohnz }
944df8bdeb3Sjohnz
945df8bdeb3Sjohnz /*
946df8bdeb3Sjohnz * throw this section into the hash
947df8bdeb3Sjohnz * use elf_rawdata for endian-independence
948df8bdeb3Sjohnz * use elf_getdata to get update of .shstrtab
949df8bdeb3Sjohnz */
950df8bdeb3Sjohnz while ((data = (shdr.sh_type == SHT_STRTAB ?
951df8bdeb3Sjohnz elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
952df8bdeb3Sjohnz if (data->d_buf == NULL) {
953df8bdeb3Sjohnz cryptodebug("elfsign_hash: %s has NULL data",
954df8bdeb3Sjohnz name);
955df8bdeb3Sjohnz continue;
956df8bdeb3Sjohnz }
957df8bdeb3Sjohnz cryptodebug("elfsign_hash: updating hash "
958df8bdeb3Sjohnz "with %s data size=%d", name, data->d_size);
959df8bdeb3Sjohnz SHA1Update(&ctx, data->d_buf, data->d_size);
960df8bdeb3Sjohnz }
961df8bdeb3Sjohnz }
962df8bdeb3Sjohnz if (elf_errmsg(0) != NULL) {
963df8bdeb3Sjohnz cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
964df8bdeb3Sjohnz elfstat = ELFSIGN_FAILED;
965df8bdeb3Sjohnz goto done;
966df8bdeb3Sjohnz }
967df8bdeb3Sjohnz
968df8bdeb3Sjohnz SHA1Final(hash, &ctx);
969df8bdeb3Sjohnz *hash_len = SHA1_DIGEST_LENGTH;
970df8bdeb3Sjohnz { /* DEBUG START */
971df8bdeb3Sjohnz const int hashstr_len = (*hash_len) * 2 + 1;
972df8bdeb3Sjohnz char *hashstr = malloc(hashstr_len);
973df8bdeb3Sjohnz
974df8bdeb3Sjohnz if (hashstr != NULL) {
975df8bdeb3Sjohnz tohexstr(hash, *hash_len, hashstr, hashstr_len);
976df8bdeb3Sjohnz cryptodebug("hash value is: %s", hashstr);
977df8bdeb3Sjohnz free(hashstr);
978df8bdeb3Sjohnz }
979df8bdeb3Sjohnz } /* DEBUG END */
980df8bdeb3Sjohnz elfstat = ELFSIGN_SUCCESS;
981df8bdeb3Sjohnz done:
982df8bdeb3Sjohnz return (elfstat);
983df8bdeb3Sjohnz }
984df8bdeb3Sjohnz
985df8bdeb3Sjohnz /*
986df8bdeb3Sjohnz * elfsign_hash - return the hash of the ELF sections affecting execution.
987df8bdeb3Sjohnz *
988df8bdeb3Sjohnz * IN: ess, hash_len
989df8bdeb3Sjohnz * OUT: hash, hash_len
990df8bdeb3Sjohnz */
991df8bdeb3Sjohnz ELFsign_status_t
elfsign_hash(ELFsign_t ess,uchar_t * hash,size_t * hash_len)992df8bdeb3Sjohnz elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
993df8bdeb3Sjohnz {
994df8bdeb3Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
995df8bdeb3Sjohnz }
996df8bdeb3Sjohnz
997df8bdeb3Sjohnz /*
998df8bdeb3Sjohnz * elfsign_hash_mem_resident - return the hash of the ELF sections
999df8bdeb3Sjohnz * with only memory resident sections.
1000df8bdeb3Sjohnz *
1001df8bdeb3Sjohnz * IN: ess, hash_len
1002df8bdeb3Sjohnz * OUT: hash, hash_len
1003df8bdeb3Sjohnz */
1004df8bdeb3Sjohnz ELFsign_status_t
elfsign_hash_mem_resident(ELFsign_t ess,uchar_t * hash,size_t * hash_len)1005df8bdeb3Sjohnz elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
1006df8bdeb3Sjohnz {
1007df8bdeb3Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
1008df8bdeb3Sjohnz }
1009df8bdeb3Sjohnz
1010df8bdeb3Sjohnz
1011df8bdeb3Sjohnz /*
1012df8bdeb3Sjohnz * elfsign_verify_signature - Verify the signature of the ELF object.
1013df8bdeb3Sjohnz *
1014df8bdeb3Sjohnz * IN: ess
1015df8bdeb3Sjohnz * OUT: esipp
1016df8bdeb3Sjohnz * RETURNS:
1017df8bdeb3Sjohnz * ELFsign_status_t
1018df8bdeb3Sjohnz */
1019df8bdeb3Sjohnz ELFsign_status_t
elfsign_verify_signature(ELFsign_t ess,struct ELFsign_sig_info ** esipp)1020df8bdeb3Sjohnz elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
1021df8bdeb3Sjohnz {
1022df8bdeb3Sjohnz ELFsign_status_t ret = ELFSIGN_FAILED;
1023df8bdeb3Sjohnz struct filesignatures *fssp;
1024df8bdeb3Sjohnz struct filesig *fsgp;
1025df8bdeb3Sjohnz size_t fslen;
1026df8bdeb3Sjohnz struct filesig_extraction fsx;
1027df8bdeb3Sjohnz uchar_t hash[SIG_MAX_LENGTH];
1028df8bdeb3Sjohnz size_t hash_len;
1029df8bdeb3Sjohnz ELFCert_t cert = NULL;
1030df8bdeb3Sjohnz int sigcnt;
1031df8bdeb3Sjohnz int nocert = 0;
1032df8bdeb3Sjohnz struct ELFsign_sig_info *esip = NULL;
1033df8bdeb3Sjohnz
1034df8bdeb3Sjohnz if (esipp != NULL) {
1035df8bdeb3Sjohnz esip = (struct ELFsign_sig_info *)
1036df8bdeb3Sjohnz calloc(1, sizeof (struct ELFsign_sig_info));
1037df8bdeb3Sjohnz *esipp = esip;
1038df8bdeb3Sjohnz }
1039df8bdeb3Sjohnz
1040df8bdeb3Sjohnz /*
1041df8bdeb3Sjohnz * Find out which cert we need, based on who signed the ELF object
1042df8bdeb3Sjohnz */
1043df8bdeb3Sjohnz if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
1044df8bdeb3Sjohnz return (ELFSIGN_NOTSIGNED);
1045df8bdeb3Sjohnz }
1046df8bdeb3Sjohnz
1047df8bdeb3Sjohnz if (fssp->filesig_cnt < 1) {
1048df8bdeb3Sjohnz ret = ELFSIGN_FAILED;
1049df8bdeb3Sjohnz goto cleanup;
1050df8bdeb3Sjohnz }
1051df8bdeb3Sjohnz
1052df8bdeb3Sjohnz fsgp = &fssp->filesig_sig;
1053df8bdeb3Sjohnz
1054df8bdeb3Sjohnz /*
1055df8bdeb3Sjohnz * Scan the signature block, looking for a verifiable signature
1056df8bdeb3Sjohnz */
1057df8bdeb3Sjohnz for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
1058df8bdeb3Sjohnz sigcnt++, fsgp = filesig_next(fsgp)) {
1059df8bdeb3Sjohnz ess->es_version = filesig_extract(fsgp, &fsx);
1060df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature: version=%s",
1061df8bdeb3Sjohnz version_to_str(ess->es_version));
1062df8bdeb3Sjohnz switch (ess->es_version) {
1063df8bdeb3Sjohnz case FILESIG_VERSION1:
1064df8bdeb3Sjohnz case FILESIG_VERSION2:
1065df8bdeb3Sjohnz case FILESIG_VERSION3:
1066df8bdeb3Sjohnz case FILESIG_VERSION4:
1067df8bdeb3Sjohnz break;
1068df8bdeb3Sjohnz default:
1069df8bdeb3Sjohnz ret = ELFSIGN_FAILED;
1070df8bdeb3Sjohnz goto cleanup;
1071df8bdeb3Sjohnz }
1072df8bdeb3Sjohnz
1073df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
1074df8bdeb3Sjohnz fsx.fsx_signer_DN);
1075df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
1076df8bdeb3Sjohnz fsx.fsx_sig_oid);
1077df8bdeb3Sjohnz /* return signer DN if requested */
1078df8bdeb3Sjohnz if (esipp != NULL) {
1079df8bdeb3Sjohnz esip->esi_format = fsx.fsx_format;
1080df8bdeb3Sjohnz if (esip->esi_signer != NULL)
1081df8bdeb3Sjohnz free(esip->esi_signer);
1082df8bdeb3Sjohnz esip->esi_signer = strdup(fsx.fsx_signer_DN);
1083df8bdeb3Sjohnz esip->esi_time = fsx.fsx_time;
1084df8bdeb3Sjohnz }
1085df8bdeb3Sjohnz
1086df8bdeb3Sjohnz /*
1087df8bdeb3Sjohnz * look for certificate
1088df8bdeb3Sjohnz */
1089df8bdeb3Sjohnz if (cert != NULL)
1090df8bdeb3Sjohnz elfcertlib_releasecert(ess, cert);
1091df8bdeb3Sjohnz
1092df8bdeb3Sjohnz /*
1093df8bdeb3Sjohnz * skip unfound certificates
1094df8bdeb3Sjohnz */
1095df8bdeb3Sjohnz if (!elfcertlib_getcert(ess, ess->es_certpath,
1096df8bdeb3Sjohnz fsx.fsx_signer_DN, &cert, ess->es_action)) {
1097df8bdeb3Sjohnz cryptodebug("unable to find certificate "
1098df8bdeb3Sjohnz "with DN=\"%s\" for %s",
1099df8bdeb3Sjohnz fsx.fsx_signer_DN, ess->es_pathname);
1100df8bdeb3Sjohnz nocert++;
1101df8bdeb3Sjohnz continue;
1102df8bdeb3Sjohnz }
1103df8bdeb3Sjohnz
1104df8bdeb3Sjohnz /*
1105df8bdeb3Sjohnz * skip unverified certificates
1106df8bdeb3Sjohnz * force verification of crypto certs
1107df8bdeb3Sjohnz */
1108df8bdeb3Sjohnz if ((ess->es_action == ES_GET_CRYPTO ||
110973556491SAnthony Scarpino ess->es_action == ES_GET_FIPS140 ||
1110df8bdeb3Sjohnz strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
1111df8bdeb3Sjohnz !elfcertlib_verifycert(ess, cert)) {
1112df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature: invalid cert");
1113df8bdeb3Sjohnz nocert++;
1114df8bdeb3Sjohnz continue;
1115df8bdeb3Sjohnz }
1116df8bdeb3Sjohnz
1117df8bdeb3Sjohnz /*
1118df8bdeb3Sjohnz * At this time the only sha1WithRSAEncryption is supported,
1119df8bdeb3Sjohnz * so check that is what we have and skip with anything else.
1120df8bdeb3Sjohnz */
1121df8bdeb3Sjohnz if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
1122df8bdeb3Sjohnz continue;
1123df8bdeb3Sjohnz }
1124df8bdeb3Sjohnz
1125df8bdeb3Sjohnz nocert = 0;
1126df8bdeb3Sjohnz /*
1127df8bdeb3Sjohnz * compute file hash
1128df8bdeb3Sjohnz */
1129df8bdeb3Sjohnz hash_len = sizeof (hash);
1130df8bdeb3Sjohnz if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
1131df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature:"
1132df8bdeb3Sjohnz " elfsign_hash failed");
1133df8bdeb3Sjohnz ret = ELFSIGN_FAILED;
1134df8bdeb3Sjohnz break;
1135df8bdeb3Sjohnz }
1136df8bdeb3Sjohnz
1137df8bdeb3Sjohnz { /* DEBUG START */
1138df8bdeb3Sjohnz const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
1139df8bdeb3Sjohnz char *sigstr = malloc(sigstr_len);
1140df8bdeb3Sjohnz
1141df8bdeb3Sjohnz if (sigstr != NULL) {
1142df8bdeb3Sjohnz tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
1143df8bdeb3Sjohnz sigstr, sigstr_len);
1144df8bdeb3Sjohnz cryptodebug("signature value is: %s", sigstr);
1145df8bdeb3Sjohnz free(sigstr);
1146df8bdeb3Sjohnz }
1147df8bdeb3Sjohnz } /* DEBUG END */
1148df8bdeb3Sjohnz
1149df8bdeb3Sjohnz if (elfcertlib_verifysig(ess, cert,
1150df8bdeb3Sjohnz fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
1151df8bdeb3Sjohnz if (ess->es_sigvercallback)
1152df8bdeb3Sjohnz (ess->es_sigvercallback)
1153df8bdeb3Sjohnz (ess->es_callbackctx, fssp, fslen, cert);
1154df8bdeb3Sjohnz /*
1155df8bdeb3Sjohnz * The signature is verified!
1156df8bdeb3Sjohnz */
1157df8bdeb3Sjohnz ret = ELFSIGN_SUCCESS;
1158df8bdeb3Sjohnz }
1159df8bdeb3Sjohnz
1160df8bdeb3Sjohnz cryptodebug("elfsign_verify_signature: invalid signature");
1161df8bdeb3Sjohnz }
1162df8bdeb3Sjohnz
1163df8bdeb3Sjohnz cleanup:
1164df8bdeb3Sjohnz if (cert != NULL)
1165df8bdeb3Sjohnz elfcertlib_releasecert(ess, cert);
1166df8bdeb3Sjohnz
1167df8bdeb3Sjohnz free(fssp);
1168df8bdeb3Sjohnz if (ret == ELFSIGN_FAILED && nocert)
1169df8bdeb3Sjohnz ret = ELFSIGN_INVALID_CERTPATH;
1170df8bdeb3Sjohnz return (ret);
1171df8bdeb3Sjohnz }
1172df8bdeb3Sjohnz
1173df8bdeb3Sjohnz
1174df8bdeb3Sjohnz static uint32_t
elfsign_switch_uint32(uint32_t i)1175df8bdeb3Sjohnz elfsign_switch_uint32(uint32_t i)
1176df8bdeb3Sjohnz {
1177df8bdeb3Sjohnz return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
1178df8bdeb3Sjohnz ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
1179df8bdeb3Sjohnz }
1180df8bdeb3Sjohnz
1181df8bdeb3Sjohnz static uint64_t
elfsign_switch_uint64(uint64_t i)1182df8bdeb3Sjohnz elfsign_switch_uint64(uint64_t i)
1183df8bdeb3Sjohnz {
1184df8bdeb3Sjohnz return (((uint64_t)elfsign_switch_uint32(i) << 32) |
1185df8bdeb3Sjohnz (elfsign_switch_uint32(i >> 32)));
1186df8bdeb3Sjohnz }
1187df8bdeb3Sjohnz
1188df8bdeb3Sjohnz /*
1189df8bdeb3Sjohnz * If appropriate, switch the endianness of the filesignatures structure
1190df8bdeb3Sjohnz * Examine the structure only when it is in native endianness
1191df8bdeb3Sjohnz */
1192df8bdeb3Sjohnz static ELFsign_status_t
elfsign_switch(ELFsign_t ess,struct filesignatures * fssp,enum ES_ACTION action)1193df8bdeb3Sjohnz elfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
1194df8bdeb3Sjohnz enum ES_ACTION action)
1195df8bdeb3Sjohnz {
1196df8bdeb3Sjohnz int fscnt;
1197df8bdeb3Sjohnz filesig_vers_t version;
1198df8bdeb3Sjohnz struct filesig *fsgp, *fsgpnext;
1199df8bdeb3Sjohnz
1200df8bdeb3Sjohnz if (ess->es_same_endian)
1201df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
1202df8bdeb3Sjohnz
1203df8bdeb3Sjohnz if (ES_ACTISUPDATE(action))
1204df8bdeb3Sjohnz fscnt = fssp->filesig_cnt;
1205df8bdeb3Sjohnz fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
1206df8bdeb3Sjohnz if (!ES_ACTISUPDATE(action))
1207df8bdeb3Sjohnz fscnt = fssp->filesig_cnt;
1208df8bdeb3Sjohnz
1209df8bdeb3Sjohnz fsgp = &(fssp)->filesig_sig;
1210df8bdeb3Sjohnz for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
1211df8bdeb3Sjohnz if (ES_ACTISUPDATE(action)) {
1212df8bdeb3Sjohnz version = fsgp->filesig_version;
1213df8bdeb3Sjohnz fsgpnext = filesig_next(fsgp);
1214df8bdeb3Sjohnz }
1215df8bdeb3Sjohnz fsgp->filesig_size =
1216df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_size);
1217df8bdeb3Sjohnz fsgp->filesig_version =
1218df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_version);
1219df8bdeb3Sjohnz if (!ES_ACTISUPDATE(action)) {
1220df8bdeb3Sjohnz version = fsgp->filesig_version;
1221df8bdeb3Sjohnz fsgpnext = filesig_next(fsgp);
1222df8bdeb3Sjohnz }
1223df8bdeb3Sjohnz switch (version) {
1224df8bdeb3Sjohnz case FILESIG_VERSION1:
1225df8bdeb3Sjohnz case FILESIG_VERSION2:
1226df8bdeb3Sjohnz fsgp->filesig_v1_dnsize =
1227df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
1228df8bdeb3Sjohnz fsgp->filesig_v1_sigsize =
1229df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
1230df8bdeb3Sjohnz fsgp->filesig_v1_oidsize =
1231df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
1232df8bdeb3Sjohnz break;
1233df8bdeb3Sjohnz case FILESIG_VERSION3:
1234df8bdeb3Sjohnz case FILESIG_VERSION4:
1235df8bdeb3Sjohnz fsgp->filesig_v3_time =
1236df8bdeb3Sjohnz elfsign_switch_uint64(fsgp->filesig_v3_time);
1237df8bdeb3Sjohnz fsgp->filesig_v3_dnsize =
1238df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
1239df8bdeb3Sjohnz fsgp->filesig_v3_sigsize =
1240df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
1241df8bdeb3Sjohnz fsgp->filesig_v3_oidsize =
1242df8bdeb3Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
1243df8bdeb3Sjohnz break;
1244df8bdeb3Sjohnz default:
1245df8bdeb3Sjohnz cryptodebug("elfsign_switch: failed");
1246df8bdeb3Sjohnz return (ELFSIGN_FAILED);
1247df8bdeb3Sjohnz }
1248df8bdeb3Sjohnz }
1249df8bdeb3Sjohnz return (ELFSIGN_SUCCESS);
1250df8bdeb3Sjohnz }
1251df8bdeb3Sjohnz
1252df8bdeb3Sjohnz /*
1253df8bdeb3Sjohnz * get/put an integer value from/to a buffer, possibly of opposite endianness
1254df8bdeb3Sjohnz */
1255df8bdeb3Sjohnz void
elfsign_buffer_len(ELFsign_t ess,size_t * ip,uchar_t * cp,enum ES_ACTION action)1256df8bdeb3Sjohnz elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
1257df8bdeb3Sjohnz enum ES_ACTION action)
1258df8bdeb3Sjohnz {
1259df8bdeb3Sjohnz uint32_t tmp;
1260df8bdeb3Sjohnz
1261df8bdeb3Sjohnz if (!ES_ACTISUPDATE(action)) {
1262df8bdeb3Sjohnz /* fetch integer from buffer */
1263df8bdeb3Sjohnz (void) memcpy(&tmp, cp, sizeof (tmp));
1264df8bdeb3Sjohnz if (!ess->es_same_endian) {
1265df8bdeb3Sjohnz tmp = elfsign_switch_uint32(tmp);
1266df8bdeb3Sjohnz }
1267df8bdeb3Sjohnz *ip = tmp;
1268df8bdeb3Sjohnz } else {
1269df8bdeb3Sjohnz /* put integer into buffer */
1270df8bdeb3Sjohnz tmp = *ip;
1271df8bdeb3Sjohnz if (!ess->es_same_endian) {
1272df8bdeb3Sjohnz tmp = elfsign_switch_uint32(tmp);
1273df8bdeb3Sjohnz }
1274df8bdeb3Sjohnz (void) memcpy(cp, &tmp, sizeof (tmp));
1275df8bdeb3Sjohnz }
1276df8bdeb3Sjohnz }
1277df8bdeb3Sjohnz
1278df8bdeb3Sjohnz char const *
elfsign_strerror(ELFsign_status_t elferror)1279df8bdeb3Sjohnz elfsign_strerror(ELFsign_status_t elferror)
1280df8bdeb3Sjohnz {
1281df8bdeb3Sjohnz char const *msg = NULL;
1282df8bdeb3Sjohnz
1283df8bdeb3Sjohnz switch (elferror) {
1284df8bdeb3Sjohnz case ELFSIGN_SUCCESS:
1285df8bdeb3Sjohnz msg = gettext("sign or verify of ELF object succeeded");
1286df8bdeb3Sjohnz break;
1287df8bdeb3Sjohnz case ELFSIGN_FAILED:
1288df8bdeb3Sjohnz msg = gettext("sign or verify of ELF object failed");
1289df8bdeb3Sjohnz break;
1290df8bdeb3Sjohnz case ELFSIGN_NOTSIGNED:
1291df8bdeb3Sjohnz msg = gettext("ELF object not signed");
1292df8bdeb3Sjohnz break;
1293df8bdeb3Sjohnz case ELFSIGN_INVALID_CERTPATH:
1294df8bdeb3Sjohnz msg = gettext("cannot access certificate");
1295df8bdeb3Sjohnz break;
1296df8bdeb3Sjohnz case ELFSIGN_INVALID_ELFOBJ:
1297df8bdeb3Sjohnz msg = gettext("unable to open as an ELF object");
1298df8bdeb3Sjohnz break;
1299df8bdeb3Sjohnz case ELFSIGN_UNKNOWN:
1300df8bdeb3Sjohnz default:
1301df8bdeb3Sjohnz msg = gettext("Unknown error");
1302df8bdeb3Sjohnz break;
1303df8bdeb3Sjohnz }
1304df8bdeb3Sjohnz
1305df8bdeb3Sjohnz return (msg);
1306df8bdeb3Sjohnz }
1307df8bdeb3Sjohnz
1308df8bdeb3Sjohnz boolean_t
elfsign_sig_info(struct filesignatures * fssp,struct ELFsign_sig_info ** esipp)1309df8bdeb3Sjohnz elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
1310df8bdeb3Sjohnz {
1311df8bdeb3Sjohnz struct filesig_extraction fsx;
1312df8bdeb3Sjohnz struct ELFsign_sig_info *esip;
1313df8bdeb3Sjohnz
1314df8bdeb3Sjohnz esip = (struct ELFsign_sig_info *)
1315df8bdeb3Sjohnz calloc(1, sizeof (struct ELFsign_sig_info));
1316df8bdeb3Sjohnz *esipp = esip;
1317df8bdeb3Sjohnz if (esip == NULL)
1318df8bdeb3Sjohnz return (B_FALSE);
1319df8bdeb3Sjohnz
1320df8bdeb3Sjohnz switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
1321df8bdeb3Sjohnz case FILESIG_VERSION1:
1322df8bdeb3Sjohnz case FILESIG_VERSION2:
1323df8bdeb3Sjohnz case FILESIG_VERSION3:
1324df8bdeb3Sjohnz case FILESIG_VERSION4:
1325df8bdeb3Sjohnz esip->esi_format = fsx.fsx_format;
1326df8bdeb3Sjohnz esip->esi_signer = strdup(fsx.fsx_signer_DN);
1327df8bdeb3Sjohnz esip->esi_time = fsx.fsx_time;
1328df8bdeb3Sjohnz break;
1329df8bdeb3Sjohnz default:
1330df8bdeb3Sjohnz free(esip);
1331df8bdeb3Sjohnz *esipp = NULL;
1332df8bdeb3Sjohnz }
1333df8bdeb3Sjohnz
1334df8bdeb3Sjohnz return (*esipp != NULL);
1335df8bdeb3Sjohnz }
1336df8bdeb3Sjohnz
1337df8bdeb3Sjohnz void
elfsign_sig_info_free(struct ELFsign_sig_info * esip)1338df8bdeb3Sjohnz elfsign_sig_info_free(struct ELFsign_sig_info *esip)
1339df8bdeb3Sjohnz {
1340df8bdeb3Sjohnz if (esip != NULL) {
1341df8bdeb3Sjohnz free(esip->esi_signer);
1342df8bdeb3Sjohnz free(esip);
1343df8bdeb3Sjohnz }
1344df8bdeb3Sjohnz }
1345