dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libelfsign / common / elfsignlib.c
blobc16716bfcd84491265c135cf49e54c08f4585c1d
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 free(fssp);
126 fssp = (struct filesignatures *)
127 malloc(filesig_ALIGN(sizeof (struct filesignatures) +
128 dn_len + sig_len + oid_len));
129 if (fssp == NULL)
130 return (fssp);
132 fssp->filesig_cnt = 1;
133 fssp->filesig_pad = 0; /* reserve for future use */
135 fsgp = &fssp->filesig_sig;
136 fsgp->filesig_size = sizeof (struct filesig) +
137 dn_len + sig_len + oid_len;
138 fsgp->filesig_version = version;
139 switch (version) {
140 case FILESIG_VERSION1:
141 case FILESIG_VERSION2:
142 fsgp->filesig_size -= sizeof (struct filesig) -
143 offsetof(struct filesig, filesig_v1_data[0]);
144 fsgp->filesig_v1_dnsize = dn_len;
145 fsgp->filesig_v1_sigsize = sig_len;
146 fsgp->filesig_v1_oidsize = oid_len;
147 fsdatap = &fsgp->filesig_v1_data[0];
148 break;
149 case FILESIG_VERSION3:
150 case FILESIG_VERSION4:
151 fsgp->filesig_size -= sizeof (struct filesig) -
152 offsetof(struct filesig, filesig_v3_data[0]);
153 fsgp->filesig_v3_time = time(NULL);
154 fsgp->filesig_v3_dnsize = dn_len;
155 fsgp->filesig_v3_sigsize = sig_len;
156 fsgp->filesig_v3_oidsize = oid_len;
157 fsdatap = &fsgp->filesig_v3_data[0];
158 break;
159 default:
160 cryptodebug("filesig_insert_dso: unknown version: %d",
161 version);
162 free(fssp);
163 return (NULL);
165 (void) memcpy(fsdatap, dn, dn_len);
166 fsdatap += dn_len;
167 (void) memcpy(fsdatap, (char *)sig, sig_len);
168 fsdatap += sig_len;
169 (void) memcpy(fsdatap, oid, oid_len);
170 fsdatap += oid_len;
171 fsgp = filesig_next(fsgp);
172 (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
174 return (fssp);
178 * filesig_extract - extract filesig structure to internal form
180 static filesig_vers_t
181 filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
183 char *fsdp;
185 #define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \
186 len_var = len_limit; \
187 if (len_var > fsgp->field) \
188 len_var = fsgp->field; \
189 (void) memcpy(data_var, cp, len_var); \
190 cp += fsgp->field; }
191 #define filesig_extract_str(cp, field, data_var, len_var) \
192 filesig_extract_common(cp, field, data_var, len_var, \
193 sizeof (data_var) - 1); \
194 data_var[len_var] = '\0';
195 #define filesig_extract_opaque(cp, field, data_var, len_var) \
196 filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
198 fsxp->fsx_version = fsgp->filesig_version;
199 cryptodebug("filesig_extract: version=%s",
200 version_to_str(fsxp->fsx_version));
201 switch (fsxp->fsx_version) {
202 case FILESIG_VERSION1:
203 case FILESIG_VERSION2:
205 * extract VERSION1 DN, signature, and OID
207 fsdp = fsgp->filesig_v1_data;
208 fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
209 fsxp->fsx_time = 0;
210 filesig_extract_str(fsdp, filesig_v1_dnsize,
211 fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
212 filesig_extract_opaque(fsdp, filesig_v1_sigsize,
213 fsxp->fsx_signature, fsxp->fsx_sig_len);
214 filesig_extract_str(fsdp, filesig_v1_oidsize,
215 fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
216 break;
217 case FILESIG_VERSION3:
218 case FILESIG_VERSION4:
219 fsdp = fsgp->filesig_v3_data;
220 fsxp->fsx_format = ES_FMT_RSA_SHA1;
221 fsxp->fsx_time = fsgp->filesig_v3_time;
222 filesig_extract_str(fsdp, filesig_v3_dnsize,
223 fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
224 filesig_extract_opaque(fsdp, filesig_v3_sigsize,
225 fsxp->fsx_signature, fsxp->fsx_sig_len);
226 filesig_extract_str(fsdp, filesig_v3_oidsize,
227 fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
228 break;
229 default:
230 break;
233 return (fsxp->fsx_version);
236 ELFsign_status_t
237 elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
239 Elf_Cmd elfcmd;
240 int oflags = 0;
241 short l_type;
242 ELFsign_t ess;
243 struct stat stb;
244 union {
245 char c[2];
246 short s;
247 } uorder;
248 GElf_Ehdr elfehdr;
249 char *ident;
251 switch (action) {
252 case ES_GET:
253 case ES_GET_CRYPTO:
254 case ES_GET_FIPS140:
255 cryptodebug("elfsign_begin for get");
256 elfcmd = ELF_C_READ;
257 oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
258 l_type = F_RDLCK;
259 break;
260 case ES_UPDATE_RSA_MD5_SHA1:
261 case ES_UPDATE_RSA_SHA1:
262 cryptodebug("elfsign_begin for update");
263 elfcmd = ELF_C_RDWR;
264 oflags = O_RDWR | O_NOCTTY | O_NDELAY;
265 l_type = F_WRLCK;
266 break;
267 default:
268 return (ELFSIGN_UNKNOWN);
271 if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
272 return (ELFSIGN_UNKNOWN);
274 (void) memset(ess, 0, sizeof (struct ELFsign_s));
276 if (!elfcertlib_init(ess)) {
277 cryptodebug("elfsign_begin: failed initialization");
278 return (ELFSIGN_UNKNOWN);
281 ess->es_elf = NULL;
282 ess->es_action = action;
283 ess->es_version = FILESIG_UNKNOWN;
284 ess->es_pathname = NULL;
285 ess->es_certpath = NULL;
287 if (filename == NULL) {
288 *essp = ess;
289 return (ELFSIGN_SUCCESS);
292 if ((ess->es_fd = open(filename, oflags)) == -1) {
293 elfsign_end(ess);
294 return (ELFSIGN_INVALID_ELFOBJ);
296 if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
297 elfsign_end(ess);
298 return (ELFSIGN_INVALID_ELFOBJ);
300 if ((ess->es_pathname = strdup(filename)) == NULL) {
301 elfsign_end(ess);
302 return (ELFSIGN_UNKNOWN);
305 * The following lock is released in elfsign_end() when we close(2)
306 * the es_fd. This ensures that we aren't trying verify a file
307 * we are currently updating.
309 ess->es_flock.l_type = l_type;
310 ess->es_flock.l_whence = SEEK_CUR;
311 ess->es_flock.l_start = 0;
312 ess->es_flock.l_len = 0;
313 if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
314 cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
315 ess->es_pathname, strerror(errno));
316 elfsign_end(ess);
317 return (ELFSIGN_UNKNOWN);
320 if (elf_version(EV_CURRENT) == EV_NONE) {
321 elfsign_end(ess);
322 return (ELFSIGN_UNKNOWN);
325 if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
326 (Elf *)NULL)) == NULL) {
327 cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
328 elfsign_end(ess);
329 return (ELFSIGN_INVALID_ELFOBJ);
332 if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
333 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
334 elfsign_end(ess);
335 return (ELFSIGN_INVALID_ELFOBJ);
337 ess->es_has_phdr = (elfehdr.e_phnum != 0);
339 uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
340 ident = elf_getident(ess->es_elf, NULL);
341 if (ident == NULL) {
342 cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
343 elfsign_end(ess);
344 return (ELFSIGN_INVALID_ELFOBJ);
346 ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
347 ess->es_ei_class = ident[EI_CLASS];
350 * Call elf_getshstrndx to be sure we have a real ELF object
351 * this is required because elf_begin doesn't check that.
353 if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
354 elfsign_end(ess);
355 cryptodebug("elfsign_begin: elf_getshstrndx failed");
356 return (ELFSIGN_INVALID_ELFOBJ);
360 * Make sure libelf doesn't rearrange section ordering / offsets.
362 (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
364 *essp = ess;
366 return (ELFSIGN_SUCCESS);
370 * elfsign_end - cleanup the ELFsign_t
372 * IN/OUT: ess
374 void
375 elfsign_end(ELFsign_t ess)
377 if (ess == NULL)
378 return;
380 if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
381 if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
382 cryptodebug("elf_update() failed: %s",
383 elf_errmsg(-1));
384 return;
388 if (ess->es_fd != -1) {
389 (void) close(ess->es_fd);
390 ess->es_fd = -1;
393 if (ess->es_pathname != NULL) {
394 free(ess->es_pathname);
395 ess->es_pathname = NULL;
397 if (ess->es_certpath != NULL) {
398 free(ess->es_certpath);
399 ess->es_certpath = NULL;
402 if (ess->es_elf != NULL) {
403 (void) elf_end(ess->es_elf);
404 ess->es_elf = NULL;
407 elfcertlib_fini(ess);
409 free(ess);
413 * set the certificate path
415 ELFsign_status_t
416 elfsign_setcertpath(ELFsign_t ess, const char *certpath)
419 * Normally use of access(2) is insecure, here we are only
420 * doing it to help provide early failure and better error
421 * checking, so there is no race condition.
423 if (access(certpath, R_OK) != 0)
424 return (ELFSIGN_INVALID_CERTPATH);
426 if ((ess->es_certpath = strdup(certpath)) == NULL)
427 return (ELFSIGN_FAILED);
429 if (ES_ACTISUPDATE(ess->es_action)) {
430 ELFCert_t cert = NULL;
431 char *subject;
433 /* set the version based on the certificate */
434 if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
435 &cert, ess->es_action)) {
436 if ((subject = elfcertlib_getdn(cert)) != NULL) {
437 if (strstr(subject, ELFSIGN_CRYPTO))
438 ess->es_version = (ess->es_action ==
439 ES_UPDATE_RSA_MD5_SHA1) ?
440 FILESIG_VERSION1 : FILESIG_VERSION3;
441 else
442 ess->es_version = (ess->es_action ==
443 ES_UPDATE_RSA_MD5_SHA1) ?
444 FILESIG_VERSION2 : FILESIG_VERSION4;
446 elfcertlib_releasecert(ess, cert);
448 if (ess->es_version == FILESIG_UNKNOWN)
449 return (ELFSIGN_FAILED);
451 return (ELFSIGN_SUCCESS);
455 * set the callback context
457 void
458 elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
460 ess->es_callbackctx = ctx;
464 * set the signature extraction callback
466 void
467 elfsign_setsigvercallback(ELFsign_t ess,
468 void (*cb)(void *, void *, size_t, ELFCert_t))
470 ess->es_sigvercallback = cb;
474 * elfsign_signatures
476 * IN: ess, fsspp, action
477 * OUT: fsspp
479 ELFsign_status_t
480 elfsign_signatures(ELFsign_t ess,
481 struct filesignatures **fsspp,
482 size_t *fslen,
483 enum ES_ACTION action)
485 Elf_Scn *scn = NULL, *sig_scn = NULL;
486 GElf_Shdr shdr;
487 Elf_Data *data = NULL;
488 const char *elf_section = SUNW_ELF_SIGNATURE_ID;
489 int fscnt, fssize;
490 struct filesig *fsgp, *fsgpnext;
491 uint64_t sig_offset = 0;
493 cryptodebug("elfsign_signature");
494 if ((ess == NULL) || (fsspp == NULL)) {
495 cryptodebug("invalid arguments");
496 return (ELFSIGN_UNKNOWN);
499 cryptodebug("elfsign_signature %s for %s",
500 ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
502 (void) elf_errno();
503 while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
504 const char *sh_name;
506 * Do a string compare to examine each section header
507 * to see if this is the section that needs to be updated.
509 if (gelf_getshdr(scn, &shdr) == NULL) {
510 cryptodebug("gelf_getshdr() failed: %s",
511 elf_errmsg(-1));
512 return (ELFSIGN_FAILED);
514 sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
515 (size_t)shdr.sh_name);
516 if (strcmp(sh_name, elf_section) == 0) {
517 cryptodebug("elfsign_signature: found %s", elf_section);
518 sig_scn = scn;
519 break;
521 if (shdr.sh_type != SHT_NOBITS &&
522 sig_offset < shdr.sh_offset + shdr.sh_size) {
523 sig_offset = shdr.sh_offset + shdr.sh_size;
526 if (elf_errmsg(0) != NULL) {
527 cryptodebug("unexpected error: %s", elf_section,
528 elf_errmsg(-1));
529 return (ELFSIGN_FAILED);
532 if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) {
533 size_t old_size, new_size;
534 char *new_d_buf;
536 cryptodebug("elfsign_signature: %s not found - creating",
537 elf_section);
540 * insert section name in .shstrtab
542 if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
543 cryptodebug("elf_getscn() failed: %s",
544 elf_errmsg(-1));
545 return (ELFSIGN_FAILED);
547 if (gelf_getshdr(scn, &shdr) == NULL) {
548 cryptodebug("gelf_getshdr() failed: %s",
549 elf_errmsg(-1));
550 return (ELFSIGN_FAILED);
552 if ((data = elf_getdata(scn, data)) == NULL) {
553 cryptodebug("elf_getdata() failed: %s",
554 elf_errmsg(-1));
555 return (ELFSIGN_FAILED);
557 old_size = data->d_size;
558 if (old_size != shdr.sh_size) {
559 cryptodebug("mismatch between data size %d "
560 "and section size %lld", old_size, shdr.sh_size);
561 return (ELFSIGN_FAILED);
563 new_size = old_size + strlen(elf_section) + 1;
564 if ((new_d_buf = malloc(new_size)) == NULL)
565 return (ELFSIGN_FAILED);
567 (void) memcpy(new_d_buf, data->d_buf, old_size);
568 (void) strlcpy(new_d_buf + old_size, elf_section,
569 new_size - old_size);
570 data->d_buf = new_d_buf;
571 data->d_size = new_size;
572 data->d_align = 1;
574 * Add the section name passed in to the end of the file.
575 * Initialize the fields in the Section Header that
576 * libelf will not fill in.
578 if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
579 cryptodebug("elf_newscn() failed: %s",
580 elf_errmsg(-1));
581 return (ELFSIGN_FAILED);
583 if (gelf_getshdr(sig_scn, &shdr) == 0) {
584 cryptodebug("gelf_getshdr() failed: %s",
585 elf_errmsg(-1));
586 return (ELFSIGN_FAILED);
588 shdr.sh_name = old_size;
589 shdr.sh_type = SHT_SUNW_SIGNATURE;
590 shdr.sh_flags = SHF_EXCLUDE;
591 shdr.sh_addr = 0;
592 shdr.sh_link = 0;
593 shdr.sh_info = 0;
594 shdr.sh_size = 0;
595 shdr.sh_offset = sig_offset;
596 shdr.sh_addralign = 1;
599 * Flush the changes to the underlying elf32 or elf64
600 * section header.
602 if (gelf_update_shdr(sig_scn, &shdr) == 0) {
603 cryptodebug("gelf_update_shdr failed");
604 return (ELFSIGN_FAILED);
607 if ((data = elf_newdata(sig_scn)) == NULL) {
608 cryptodebug("can't add elf data area for %s: %s",
609 elf_section, elf_errmsg(-1));
610 return (ELFSIGN_FAILED);
612 if (elfsign_adjustoffsets(ess, scn,
613 old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
614 cryptodebug("can't adjust for new section name %s",
615 elf_section);
616 return (ELFSIGN_FAILED);
618 } else {
619 if (sig_scn == NULL) {
620 cryptodebug("can't find signature section");
621 *fsspp = NULL;
622 return (ELFSIGN_NOTSIGNED);
624 if ((data = elf_getdata(sig_scn, NULL)) == 0) {
625 cryptodebug("can't get section data for %s",
626 elf_section);
627 return (ELFSIGN_FAILED);
631 if (ES_ACTISUPDATE(action)) {
632 fssize = offsetof(struct filesignatures, _u1);
633 if (*fsspp != NULL) {
634 fsgp = &(*fsspp)->filesig_sig;
635 for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
636 fscnt++) {
637 fsgpnext = filesig_next(fsgp);
638 fssize += (char *)(fsgpnext) - (char *)(fsgp);
639 fsgp = fsgpnext;
642 if (shdr.sh_addr != 0) {
643 cryptodebug("section %s is part of a loadable segment, "
644 "it cannot be changed.\n", elf_section);
645 return (ELFSIGN_FAILED);
647 if ((data->d_buf = malloc(fssize)) == NULL)
648 return (ELFSIGN_FAILED);
649 if (*fsspp != NULL) {
650 (void) memcpy(data->d_buf, *fsspp, fssize);
651 (void) elfsign_switch(ess,
652 (struct filesignatures *)data->d_buf, action);
654 data->d_size = fssize;
655 data->d_align = 1;
656 data->d_type = ELF_T_BYTE;
657 cryptodebug("elfsign_signature: data->d_size = %d",
658 data->d_size);
659 if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
660 ELFSIGN_SUCCESS) {
661 cryptodebug("can't adjust for revised signature "
662 "section contents");
663 return (ELFSIGN_FAILED);
665 } else {
666 *fsspp = malloc(data->d_size);
667 if (*fsspp == NULL)
668 return (ELFSIGN_FAILED);
669 (void) memcpy(*fsspp, data->d_buf, data->d_size);
670 if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
671 free(*fsspp);
672 *fsspp = NULL;
673 return (ELFSIGN_FAILED);
675 *fslen = data->d_size;
678 return (ELFSIGN_SUCCESS);
681 static ELFsign_status_t
682 elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
684 GElf_Ehdr elfehdr;
685 GElf_Shdr shdr;
686 uint64_t prev_end, scn_offset;
687 char *name;
688 Elf_Scn *scnp;
689 Elf_Data *data;
690 ELFsign_status_t retval = ELFSIGN_FAILED;
691 struct scninfo {
692 struct scninfo *scni_next;
693 Elf_Scn *scni_scn;
694 uint64_t scni_offset;
695 } *scnip = NULL, *tmpscnip, **scnipp;
697 /* get the size of the current section */
698 if (gelf_getshdr(scn, &shdr) == NULL)
699 return (ELFSIGN_FAILED);
700 if (shdr.sh_size == new_size)
701 return (ELFSIGN_SUCCESS);
702 scn_offset = shdr.sh_offset;
703 name = elf_strptr(ess->es_elf, ess->es_shstrndx,
704 (size_t)shdr.sh_name);
705 if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
706 cryptodebug("elfsign_adjustoffsets: "
707 "can't move allocated section %s", name ? name : "NULL");
708 return (ELFSIGN_FAILED);
711 /* resize the desired section */
712 cryptodebug("elfsign_adjustoffsets: "
713 "resizing %s at 0x%llx from 0x%llx to 0x%llx",
714 name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
715 shdr.sh_size = new_size;
716 if (gelf_update_shdr(scn, &shdr) == 0) {
717 cryptodebug("gelf_update_shdr failed");
718 goto bad;
720 prev_end = shdr.sh_offset + shdr.sh_size;
723 * find sections whose data follows the changed section
724 * must scan all sections since section data may not
725 * be in same order as section headers
727 scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */
728 while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
729 if (gelf_getshdr(scnp, &shdr) == NULL)
730 goto bad;
731 if (shdr.sh_offset <= scn_offset)
732 continue;
733 name = elf_strptr(ess->es_elf, ess->es_shstrndx,
734 (size_t)shdr.sh_name);
735 if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
736 if (shdr.sh_type == SHT_NOBITS) {
737 /* .bss can occasionally overlap .shrtab */
738 continue;
740 cryptodebug("elfsign_adjustoffsets: "
741 "can't move allocated section %s",
742 name ? name : "NULL");
743 goto bad;
746 * force reading of data to memory image
748 data = NULL;
749 while ((data = elf_rawdata(scnp, data)) != NULL)
752 * capture section information
753 * insert into list in order of sh_offset
755 cryptodebug("elfsign_adjustoffsets: "
756 "may have to adjust section %s, offset 0x%llx",
757 name ? name : "NULL", shdr.sh_offset);
758 tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
759 if (tmpscnip == NULL) {
760 cryptodebug("elfsign_adjustoffsets: "
761 "memory allocation failure");
762 goto bad;
764 tmpscnip->scni_scn = scnp;
765 tmpscnip->scni_offset = shdr.sh_offset;
766 for (scnipp = &scnip; *scnipp != NULL;
767 scnipp = &(*scnipp)->scni_next) {
768 if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
769 break;
771 tmpscnip->scni_next = *scnipp;
772 *scnipp = tmpscnip;
775 /* move following sections as necessary */
776 for (tmpscnip = scnip; tmpscnip != NULL;
777 tmpscnip = tmpscnip->scni_next) {
778 scnp = tmpscnip->scni_scn;
779 if (gelf_getshdr(scnp, &shdr) == NULL) {
780 cryptodebug("elfsign_adjustoffsets: "
781 "elf_getshdr for section %d failed",
782 elf_ndxscn(scnp));
783 goto bad;
785 if (shdr.sh_offset >= prev_end)
786 break;
787 prev_end = (prev_end + shdr.sh_addralign - 1) &
788 (-shdr.sh_addralign);
789 name = elf_strptr(ess->es_elf, ess->es_shstrndx,
790 (size_t)shdr.sh_name);
791 cryptodebug("elfsign_adjustoffsets: "
792 "moving %s size 0x%llx from 0x%llx to 0x%llx",
793 name ? name : "NULL", shdr.sh_size,
794 shdr.sh_offset, prev_end);
795 shdr.sh_offset = prev_end;
796 if (gelf_update_shdr(scnp, &shdr) == 0) {
797 cryptodebug("gelf_update_shdr failed");
798 goto bad;
800 prev_end = shdr.sh_offset + shdr.sh_size;
804 * adjust section header offset in elf header
806 if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
807 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
808 goto bad;
810 if (elfehdr.e_shoff < prev_end) {
811 if (ess->es_ei_class == ELFCLASS32)
812 prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
813 (-ELF32_FSZ_OFF);
814 else if (ess->es_ei_class == ELFCLASS64)
815 prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
816 (-ELF64_FSZ_OFF);
817 cryptodebug("elfsign_adjustoffsets: "
818 "move sh_off from 0x%llx to 0x%llx",
819 elfehdr.e_shoff, prev_end);
820 elfehdr.e_shoff = prev_end;
821 if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
822 cryptodebug("elf_update_ehdr() failed: %s",
823 elf_errmsg(-1));
824 goto bad;
828 retval = ELFSIGN_SUCCESS;
830 bad:
831 while (scnip != NULL) {
832 tmpscnip = scnip->scni_next;
833 free(scnip);
834 scnip = tmpscnip;
836 return (retval);
839 struct filesignatures *
840 elfsign_insert_dso(ELFsign_t ess,
841 struct filesignatures *fssp,
842 const char *dn,
843 int dn_len,
844 const uchar_t *sig,
845 int sig_len,
846 const char *oid,
847 int oid_len)
849 return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
850 sig, sig_len, oid, oid_len));
853 /*ARGSUSED*/
854 filesig_vers_t
855 elfsign_extract_sig(ELFsign_t ess,
856 struct filesignatures *fssp,
857 uchar_t *sig,
858 size_t *sig_len)
860 struct filesig_extraction fsx;
861 filesig_vers_t version;
863 if (fssp == NULL)
864 return (FILESIG_UNKNOWN);
865 if (fssp->filesig_cnt != 1)
866 return (FILESIG_UNKNOWN);
867 version = filesig_extract(&fssp->filesig_sig, &fsx);
868 switch (version) {
869 case FILESIG_VERSION1:
870 case FILESIG_VERSION2:
871 case FILESIG_VERSION3:
872 case FILESIG_VERSION4:
873 if (*sig_len >= fsx.fsx_sig_len) {
874 (void) memcpy((char *)sig, (char *)fsx.fsx_signature,
875 *sig_len);
876 *sig_len = fsx.fsx_sig_len;
877 } else
878 version = FILESIG_UNKNOWN;
879 break;
880 default:
881 version = FILESIG_UNKNOWN;
882 break;
885 if (ess->es_version == FILESIG_UNKNOWN) {
886 ess->es_version = version;
889 return (version);
892 static ELFsign_status_t
893 elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
894 boolean_t hash_mem_resident)
896 Elf_Scn *scn = NULL;
897 ELFsign_status_t elfstat;
898 GElf_Shdr shdr;
899 SHA1_CTX ctx;
901 /* The buffer must be large enough to hold the hash */
902 if (*hash_len < SHA1_DIGEST_LENGTH)
903 return (ELFSIGN_FAILED);
905 bzero(hash, *hash_len);
907 /* Initialize the digest session */
908 SHA1Init(&ctx);
910 scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */
911 (void) elf_errno();
912 while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
913 char *name = NULL;
914 Elf_Data *data = NULL;
916 if (gelf_getshdr(scn, &shdr) == NULL) {
917 elfstat = ELFSIGN_FAILED;
918 goto done;
921 name = elf_strptr(ess->es_elf, ess->es_shstrndx,
922 (size_t)shdr.sh_name);
923 if (name == NULL)
924 name = "NULL";
926 if (!hash_mem_resident &&
927 (ess->es_version == FILESIG_VERSION1 ||
928 ess->es_version == FILESIG_VERSION3)) {
930 * skip the signature section only
932 if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
933 cryptodebug("elfsign_hash: skipping %s", name);
934 continue;
936 } else if (!(shdr.sh_flags & SHF_ALLOC)) {
938 * select only memory resident sections
940 cryptodebug("elfsign_hash: skipping %s", name);
941 continue;
945 * throw this section into the hash
946 * use elf_rawdata for endian-independence
947 * use elf_getdata to get update of .shstrtab
949 while ((data = (shdr.sh_type == SHT_STRTAB ?
950 elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
951 if (data->d_buf == NULL) {
952 cryptodebug("elfsign_hash: %s has NULL data",
953 name);
954 continue;
956 cryptodebug("elfsign_hash: updating hash "
957 "with %s data size=%d", name, data->d_size);
958 SHA1Update(&ctx, data->d_buf, data->d_size);
961 if (elf_errmsg(0) != NULL) {
962 cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
963 elfstat = ELFSIGN_FAILED;
964 goto done;
967 SHA1Final(hash, &ctx);
968 *hash_len = SHA1_DIGEST_LENGTH;
969 { /* DEBUG START */
970 const int hashstr_len = (*hash_len) * 2 + 1;
971 char *hashstr = malloc(hashstr_len);
973 if (hashstr != NULL) {
974 tohexstr(hash, *hash_len, hashstr, hashstr_len);
975 cryptodebug("hash value is: %s", hashstr);
976 free(hashstr);
978 } /* DEBUG END */
979 elfstat = ELFSIGN_SUCCESS;
980 done:
981 return (elfstat);
985 * elfsign_hash - return the hash of the ELF sections affecting execution.
987 * IN: ess, hash_len
988 * OUT: hash, hash_len
990 ELFsign_status_t
991 elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
993 return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
997 * elfsign_hash_mem_resident - return the hash of the ELF sections
998 * with only memory resident sections.
1000 * IN: ess, hash_len
1001 * OUT: hash, hash_len
1003 ELFsign_status_t
1004 elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
1006 return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
1011 * elfsign_verify_signature - Verify the signature of the ELF object.
1013 * IN: ess
1014 * OUT: esipp
1015 * RETURNS:
1016 * ELFsign_status_t
1018 ELFsign_status_t
1019 elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
1021 ELFsign_status_t ret = ELFSIGN_FAILED;
1022 struct filesignatures *fssp;
1023 struct filesig *fsgp;
1024 size_t fslen;
1025 struct filesig_extraction fsx;
1026 uchar_t hash[SIG_MAX_LENGTH];
1027 size_t hash_len;
1028 ELFCert_t cert = NULL;
1029 int sigcnt;
1030 int nocert = 0;
1031 struct ELFsign_sig_info *esip = NULL;
1033 if (esipp != NULL) {
1034 esip = (struct ELFsign_sig_info *)
1035 calloc(1, sizeof (struct ELFsign_sig_info));
1036 *esipp = esip;
1040 * Find out which cert we need, based on who signed the ELF object
1042 if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
1043 return (ELFSIGN_NOTSIGNED);
1046 if (fssp->filesig_cnt < 1) {
1047 ret = ELFSIGN_FAILED;
1048 goto cleanup;
1051 fsgp = &fssp->filesig_sig;
1054 * Scan the signature block, looking for a verifiable signature
1056 for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
1057 sigcnt++, fsgp = filesig_next(fsgp)) {
1058 ess->es_version = filesig_extract(fsgp, &fsx);
1059 cryptodebug("elfsign_verify_signature: version=%s",
1060 version_to_str(ess->es_version));
1061 switch (ess->es_version) {
1062 case FILESIG_VERSION1:
1063 case FILESIG_VERSION2:
1064 case FILESIG_VERSION3:
1065 case FILESIG_VERSION4:
1066 break;
1067 default:
1068 ret = ELFSIGN_FAILED;
1069 goto cleanup;
1072 cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
1073 fsx.fsx_signer_DN);
1074 cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
1075 fsx.fsx_sig_oid);
1076 /* return signer DN if requested */
1077 if (esipp != NULL) {
1078 esip->esi_format = fsx.fsx_format;
1079 free(esip->esi_signer);
1080 esip->esi_signer = strdup(fsx.fsx_signer_DN);
1081 esip->esi_time = fsx.fsx_time;
1085 * look for certificate
1087 if (cert != NULL)
1088 elfcertlib_releasecert(ess, cert);
1091 * skip unfound certificates
1093 if (!elfcertlib_getcert(ess, ess->es_certpath,
1094 fsx.fsx_signer_DN, &cert, ess->es_action)) {
1095 cryptodebug("unable to find certificate "
1096 "with DN=\"%s\" for %s",
1097 fsx.fsx_signer_DN, ess->es_pathname);
1098 nocert++;
1099 continue;
1103 * skip unverified certificates
1104 * force verification of crypto certs
1106 if ((ess->es_action == ES_GET_CRYPTO ||
1107 ess->es_action == ES_GET_FIPS140 ||
1108 strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
1109 !elfcertlib_verifycert(ess, cert)) {
1110 cryptodebug("elfsign_verify_signature: invalid cert");
1111 nocert++;
1112 continue;
1116 * At this time the only sha1WithRSAEncryption is supported,
1117 * so check that is what we have and skip with anything else.
1119 if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
1120 continue;
1123 nocert = 0;
1125 * compute file hash
1127 hash_len = sizeof (hash);
1128 if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
1129 cryptodebug("elfsign_verify_signature:"
1130 " elfsign_hash failed");
1131 ret = ELFSIGN_FAILED;
1132 break;
1135 { /* DEBUG START */
1136 const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
1137 char *sigstr = malloc(sigstr_len);
1139 if (sigstr != NULL) {
1140 tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
1141 sigstr, sigstr_len);
1142 cryptodebug("signature value is: %s", sigstr);
1143 free(sigstr);
1145 } /* DEBUG END */
1147 if (elfcertlib_verifysig(ess, cert,
1148 fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
1149 if (ess->es_sigvercallback)
1150 (ess->es_sigvercallback)
1151 (ess->es_callbackctx, fssp, fslen, cert);
1153 * The signature is verified!
1155 ret = ELFSIGN_SUCCESS;
1158 cryptodebug("elfsign_verify_signature: invalid signature");
1161 cleanup:
1162 if (cert != NULL)
1163 elfcertlib_releasecert(ess, cert);
1165 free(fssp);
1166 if (ret == ELFSIGN_FAILED && nocert)
1167 ret = ELFSIGN_INVALID_CERTPATH;
1168 return (ret);
1172 static uint32_t
1173 elfsign_switch_uint32(uint32_t i)
1175 return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
1176 ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
1179 static uint64_t
1180 elfsign_switch_uint64(uint64_t i)
1182 return (((uint64_t)elfsign_switch_uint32(i) << 32) |
1183 (elfsign_switch_uint32(i >> 32)));
1187 * If appropriate, switch the endianness of the filesignatures structure
1188 * Examine the structure only when it is in native endianness
1190 static ELFsign_status_t
1191 elfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
1192 enum ES_ACTION action)
1194 int fscnt;
1195 filesig_vers_t version;
1196 struct filesig *fsgp, *fsgpnext;
1198 if (ess->es_same_endian)
1199 return (ELFSIGN_SUCCESS);
1201 if (ES_ACTISUPDATE(action))
1202 fscnt = fssp->filesig_cnt;
1203 fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
1204 if (!ES_ACTISUPDATE(action))
1205 fscnt = fssp->filesig_cnt;
1207 fsgp = &(fssp)->filesig_sig;
1208 for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
1209 if (ES_ACTISUPDATE(action)) {
1210 version = fsgp->filesig_version;
1211 fsgpnext = filesig_next(fsgp);
1213 fsgp->filesig_size =
1214 elfsign_switch_uint32(fsgp->filesig_size);
1215 fsgp->filesig_version =
1216 elfsign_switch_uint32(fsgp->filesig_version);
1217 if (!ES_ACTISUPDATE(action)) {
1218 version = fsgp->filesig_version;
1219 fsgpnext = filesig_next(fsgp);
1221 switch (version) {
1222 case FILESIG_VERSION1:
1223 case FILESIG_VERSION2:
1224 fsgp->filesig_v1_dnsize =
1225 elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
1226 fsgp->filesig_v1_sigsize =
1227 elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
1228 fsgp->filesig_v1_oidsize =
1229 elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
1230 break;
1231 case FILESIG_VERSION3:
1232 case FILESIG_VERSION4:
1233 fsgp->filesig_v3_time =
1234 elfsign_switch_uint64(fsgp->filesig_v3_time);
1235 fsgp->filesig_v3_dnsize =
1236 elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
1237 fsgp->filesig_v3_sigsize =
1238 elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
1239 fsgp->filesig_v3_oidsize =
1240 elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
1241 break;
1242 default:
1243 cryptodebug("elfsign_switch: failed");
1244 return (ELFSIGN_FAILED);
1247 return (ELFSIGN_SUCCESS);
1251 * get/put an integer value from/to a buffer, possibly of opposite endianness
1253 void
1254 elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
1255 enum ES_ACTION action)
1257 uint32_t tmp;
1259 if (!ES_ACTISUPDATE(action)) {
1260 /* fetch integer from buffer */
1261 (void) memcpy(&tmp, cp, sizeof (tmp));
1262 if (!ess->es_same_endian) {
1263 tmp = elfsign_switch_uint32(tmp);
1265 *ip = tmp;
1266 } else {
1267 /* put integer into buffer */
1268 tmp = *ip;
1269 if (!ess->es_same_endian) {
1270 tmp = elfsign_switch_uint32(tmp);
1272 (void) memcpy(cp, &tmp, sizeof (tmp));
1276 char const *
1277 elfsign_strerror(ELFsign_status_t elferror)
1279 char const *msg = NULL;
1281 switch (elferror) {
1282 case ELFSIGN_SUCCESS:
1283 msg = gettext("sign or verify of ELF object succeeded");
1284 break;
1285 case ELFSIGN_FAILED:
1286 msg = gettext("sign or verify of ELF object failed");
1287 break;
1288 case ELFSIGN_NOTSIGNED:
1289 msg = gettext("ELF object not signed");
1290 break;
1291 case ELFSIGN_INVALID_CERTPATH:
1292 msg = gettext("cannot access certificate");
1293 break;
1294 case ELFSIGN_INVALID_ELFOBJ:
1295 msg = gettext("unable to open as an ELF object");
1296 break;
1297 case ELFSIGN_UNKNOWN:
1298 default:
1299 msg = gettext("Unknown error");
1300 break;
1303 return (msg);
1306 boolean_t
1307 elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
1309 struct filesig_extraction fsx;
1310 struct ELFsign_sig_info *esip;
1312 esip = (struct ELFsign_sig_info *)
1313 calloc(1, sizeof (struct ELFsign_sig_info));
1314 *esipp = esip;
1315 if (esip == NULL)
1316 return (B_FALSE);
1318 switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
1319 case FILESIG_VERSION1:
1320 case FILESIG_VERSION2:
1321 case FILESIG_VERSION3:
1322 case FILESIG_VERSION4:
1323 esip->esi_format = fsx.fsx_format;
1324 esip->esi_signer = strdup(fsx.fsx_signer_DN);
1325 esip->esi_time = fsx.fsx_time;
1326 break;
1327 default:
1328 free(esip);
1329 *esipp = NULL;
1332 return (*esipp != NULL);
1335 void
1336 elfsign_sig_info_free(struct ELFsign_sig_info *esip)
1338 if (esip != NULL) {
1339 free(esip->esi_signer);
1340 free(esip);