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]
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>
40 #include <cryptoutil.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
;
61 char fsx_signer_DN
[ELFCERT_MAX_DN_LEN
];
62 size_t fsx_signer_DN_len
;
63 uchar_t fsx_signature
[SIG_MAX_LENGTH
];
65 char fsx_sig_oid
[100];
66 size_t fsx_sig_oid_len
;
71 version_to_str(filesig_vers_t v
)
76 case FILESIG_VERSION1
:
79 case FILESIG_VERSION2
:
82 case FILESIG_VERSION3
:
85 case FILESIG_VERSION4
:
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
,
109 struct filesig
*fsgp
;
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
126 fssp
= (struct filesignatures
*)
127 malloc(filesig_ALIGN(sizeof (struct filesignatures
) +
128 dn_len
+ sig_len
+ oid_len
));
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
;
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];
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];
160 cryptodebug("filesig_insert_dso: unknown version: %d",
165 (void) memcpy(fsdatap
, dn
, dn_len
);
167 (void) memcpy(fsdatap
, (char *)sig
, sig_len
);
169 (void) memcpy(fsdatap
, oid
, oid_len
);
171 fsgp
= filesig_next(fsgp
);
172 (void) memset(fsdatap
, 0, (char *)(fsgp
) - fsdatap
);
178 * filesig_extract - extract filesig structure to internal form
180 static filesig_vers_t
181 filesig_extract(struct filesig
*fsgp
, struct filesig_extraction
*fsxp
)
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); \
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
;
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
);
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
);
233 return (fsxp
->fsx_version
);
237 elfsign_begin(const char *filename
, enum ES_ACTION action
, ELFsign_t
*essp
)
255 cryptodebug("elfsign_begin for get");
257 oflags
= O_RDONLY
| O_NOCTTY
| O_NDELAY
;
260 case ES_UPDATE_RSA_MD5_SHA1
:
261 case ES_UPDATE_RSA_SHA1
:
262 cryptodebug("elfsign_begin for update");
264 oflags
= O_RDWR
| O_NOCTTY
| O_NDELAY
;
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
);
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
) {
289 return (ELFSIGN_SUCCESS
);
292 if ((ess
->es_fd
= open(filename
, oflags
)) == -1) {
294 return (ELFSIGN_INVALID_ELFOBJ
);
296 if ((fstat(ess
->es_fd
, &stb
) == -1) || !S_ISREG(stb
.st_mode
)) {
298 return (ELFSIGN_INVALID_ELFOBJ
);
300 if ((ess
->es_pathname
= strdup(filename
)) == NULL
) {
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
));
317 return (ELFSIGN_UNKNOWN
);
320 if (elf_version(EV_CURRENT
) == EV_NONE
) {
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));
329 return (ELFSIGN_INVALID_ELFOBJ
);
332 if (gelf_getehdr(ess
->es_elf
, &elfehdr
) == NULL
) {
333 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
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
);
342 cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
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) {
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
);
366 return (ELFSIGN_SUCCESS
);
370 * elfsign_end - cleanup the ELFsign_t
375 elfsign_end(ELFsign_t ess
)
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",
388 if (ess
->es_fd
!= -1) {
389 (void) close(ess
->es_fd
);
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
);
407 elfcertlib_fini(ess
);
413 * set the certificate path
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
;
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
;
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
458 elfsign_setcallbackctx(ELFsign_t ess
, void *ctx
)
460 ess
->es_callbackctx
= ctx
;
464 * set the signature extraction callback
467 elfsign_setsigvercallback(ELFsign_t ess
,
468 void (*cb
)(void *, void *, size_t, ELFCert_t
))
470 ess
->es_sigvercallback
= cb
;
476 * IN: ess, fsspp, action
480 elfsign_signatures(ELFsign_t ess
,
481 struct filesignatures
**fsspp
,
483 enum ES_ACTION action
)
485 Elf_Scn
*scn
= NULL
, *sig_scn
= NULL
;
487 Elf_Data
*data
= NULL
;
488 const char *elf_section
= SUNW_ELF_SIGNATURE_ID
;
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
);
503 while ((scn
= elf_nextscn(ess
->es_elf
, scn
)) != NULL
) {
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",
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
);
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
,
529 return (ELFSIGN_FAILED
);
532 if (ES_ACTISUPDATE(action
) && (sig_scn
== NULL
)) {
533 size_t old_size
, new_size
;
536 cryptodebug("elfsign_signature: %s not found - creating",
540 * insert section name in .shstrtab
542 if ((scn
= elf_getscn(ess
->es_elf
, ess
->es_shstrndx
)) == 0) {
543 cryptodebug("elf_getscn() failed: %s",
545 return (ELFSIGN_FAILED
);
547 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
548 cryptodebug("gelf_getshdr() failed: %s",
550 return (ELFSIGN_FAILED
);
552 if ((data
= elf_getdata(scn
, data
)) == NULL
) {
553 cryptodebug("elf_getdata() failed: %s",
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
;
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",
581 return (ELFSIGN_FAILED
);
583 if (gelf_getshdr(sig_scn
, &shdr
) == 0) {
584 cryptodebug("gelf_getshdr() failed: %s",
586 return (ELFSIGN_FAILED
);
588 shdr
.sh_name
= old_size
;
589 shdr
.sh_type
= SHT_SUNW_SIGNATURE
;
590 shdr
.sh_flags
= SHF_EXCLUDE
;
595 shdr
.sh_offset
= sig_offset
;
596 shdr
.sh_addralign
= 1;
599 * Flush the changes to the underlying elf32 or elf64
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",
616 return (ELFSIGN_FAILED
);
619 if (sig_scn
== NULL
) {
620 cryptodebug("can't find signature section");
622 return (ELFSIGN_NOTSIGNED
);
624 if ((data
= elf_getdata(sig_scn
, NULL
)) == 0) {
625 cryptodebug("can't get section data for %s",
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
;
637 fsgpnext
= filesig_next(fsgp
);
638 fssize
+= (char *)(fsgpnext
) - (char *)(fsgp
);
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
;
656 data
->d_type
= ELF_T_BYTE
;
657 cryptodebug("elfsign_signature: data->d_size = %d",
659 if (elfsign_adjustoffsets(ess
, sig_scn
, fssize
) !=
661 cryptodebug("can't adjust for revised signature "
663 return (ELFSIGN_FAILED
);
666 *fsspp
= malloc(data
->d_size
);
668 return (ELFSIGN_FAILED
);
669 (void) memcpy(*fsspp
, data
->d_buf
, data
->d_size
);
670 if (elfsign_switch(ess
, *fsspp
, ES_GET
) != ELFSIGN_SUCCESS
) {
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
)
686 uint64_t prev_end
, scn_offset
;
690 ELFsign_status_t retval
= ELFSIGN_FAILED
;
692 struct scninfo
*scni_next
;
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");
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
)
731 if (shdr
.sh_offset
<= scn_offset
)
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 */
740 cryptodebug("elfsign_adjustoffsets: "
741 "can't move allocated section %s",
742 name
? name
: "NULL");
746 * force reading of data to memory image
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");
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
)
771 tmpscnip
->scni_next
= *scnipp
;
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",
785 if (shdr
.sh_offset
>= prev_end
)
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");
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));
810 if (elfehdr
.e_shoff
< prev_end
) {
811 if (ess
->es_ei_class
== ELFCLASS32
)
812 prev_end
= (prev_end
+ ELF32_FSZ_OFF
- 1) &
814 else if (ess
->es_ei_class
== ELFCLASS64
)
815 prev_end
= (prev_end
+ ELF64_FSZ_OFF
- 1) &
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",
828 retval
= ELFSIGN_SUCCESS
;
831 while (scnip
!= NULL
) {
832 tmpscnip
= scnip
->scni_next
;
839 struct filesignatures
*
840 elfsign_insert_dso(ELFsign_t ess
,
841 struct filesignatures
*fssp
,
849 return (filesig_insert_dso(fssp
, ess
->es_version
, dn
, dn_len
,
850 sig
, sig_len
, oid
, oid_len
));
855 elfsign_extract_sig(ELFsign_t ess
,
856 struct filesignatures
*fssp
,
860 struct filesig_extraction fsx
;
861 filesig_vers_t version
;
864 return (FILESIG_UNKNOWN
);
865 if (fssp
->filesig_cnt
!= 1)
866 return (FILESIG_UNKNOWN
);
867 version
= filesig_extract(&fssp
->filesig_sig
, &fsx
);
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
,
876 *sig_len
= fsx
.fsx_sig_len
;
878 version
= FILESIG_UNKNOWN
;
881 version
= FILESIG_UNKNOWN
;
885 if (ess
->es_version
== FILESIG_UNKNOWN
) {
886 ess
->es_version
= 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
)
897 ELFsign_status_t elfstat
;
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 */
910 scn
= elf_getscn(ess
->es_elf
, 0); /* "seek" to start */
912 while ((scn
= elf_nextscn(ess
->es_elf
, scn
)) != 0) {
914 Elf_Data
*data
= NULL
;
916 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
917 elfstat
= ELFSIGN_FAILED
;
921 name
= elf_strptr(ess
->es_elf
, ess
->es_shstrndx
,
922 (size_t)shdr
.sh_name
);
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
);
936 } else if (!(shdr
.sh_flags
& SHF_ALLOC
)) {
938 * select only memory resident sections
940 cryptodebug("elfsign_hash: skipping %s", name
);
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",
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
;
967 SHA1Final(hash
, &ctx
);
968 *hash_len
= SHA1_DIGEST_LENGTH
;
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
);
979 elfstat
= ELFSIGN_SUCCESS
;
985 * elfsign_hash - return the hash of the ELF sections affecting execution.
988 * OUT: hash, hash_len
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.
1001 * OUT: hash, hash_len
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.
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
;
1025 struct filesig_extraction fsx
;
1026 uchar_t hash
[SIG_MAX_LENGTH
];
1028 ELFCert_t cert
= NULL
;
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
));
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
;
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
:
1068 ret
= ELFSIGN_FAILED
;
1072 cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
1074 cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
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
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
);
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");
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) {
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
;
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
);
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");
1163 elfcertlib_releasecert(ess
, cert
);
1166 if (ret
== ELFSIGN_FAILED
&& nocert
)
1167 ret
= ELFSIGN_INVALID_CERTPATH
;
1173 elfsign_switch_uint32(uint32_t i
)
1175 return (((i
& 0xff) << 24) | ((i
& 0xff00) << 8) |
1176 ((i
>> 8) & 0xff00) | ((i
>> 24) & 0xff));
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
)
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
);
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
);
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
);
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
1254 elfsign_buffer_len(ELFsign_t ess
, size_t *ip
, uchar_t
*cp
,
1255 enum ES_ACTION action
)
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
);
1267 /* put integer into buffer */
1269 if (!ess
->es_same_endian
) {
1270 tmp
= elfsign_switch_uint32(tmp
);
1272 (void) memcpy(cp
, &tmp
, sizeof (tmp
));
1277 elfsign_strerror(ELFsign_status_t elferror
)
1279 char const *msg
= NULL
;
1282 case ELFSIGN_SUCCESS
:
1283 msg
= gettext("sign or verify of ELF object succeeded");
1285 case ELFSIGN_FAILED
:
1286 msg
= gettext("sign or verify of ELF object failed");
1288 case ELFSIGN_NOTSIGNED
:
1289 msg
= gettext("ELF object not signed");
1291 case ELFSIGN_INVALID_CERTPATH
:
1292 msg
= gettext("cannot access certificate");
1294 case ELFSIGN_INVALID_ELFOBJ
:
1295 msg
= gettext("unable to open as an ELF object");
1297 case ELFSIGN_UNKNOWN
:
1299 msg
= gettext("Unknown error");
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
));
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
;
1332 return (*esipp
!= NULL
);
1336 elfsign_sig_info_free(struct ELFsign_sig_info
*esip
)
1339 free(esip
->esi_signer
);