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