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
127 fssp
= (struct filesignatures
*)
128 malloc(filesig_ALIGN(sizeof (struct filesignatures
) +
129 dn_len
+ sig_len
+ oid_len
));
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
;
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];
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];
161 cryptodebug("filesig_insert_dso: unknown version: %d",
166 (void) memcpy(fsdatap
, dn
, dn_len
);
168 (void) memcpy(fsdatap
, (char *)sig
, sig_len
);
170 (void) memcpy(fsdatap
, oid
, oid_len
);
172 fsgp
= filesig_next(fsgp
);
173 (void) memset(fsdatap
, 0, (char *)(fsgp
) - fsdatap
);
179 * filesig_extract - extract filesig structure to internal form
181 static filesig_vers_t
182 filesig_extract(struct filesig
*fsgp
, struct filesig_extraction
*fsxp
)
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); \
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
;
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
);
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
);
234 return (fsxp
->fsx_version
);
238 elfsign_begin(const char *filename
, enum ES_ACTION action
, ELFsign_t
*essp
)
256 cryptodebug("elfsign_begin for get");
258 oflags
= O_RDONLY
| O_NOCTTY
| O_NDELAY
;
261 case ES_UPDATE_RSA_MD5_SHA1
:
262 case ES_UPDATE_RSA_SHA1
:
263 cryptodebug("elfsign_begin for update");
265 oflags
= O_RDWR
| O_NOCTTY
| O_NDELAY
;
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
);
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
) {
290 return (ELFSIGN_SUCCESS
);
293 if ((ess
->es_fd
= open(filename
, oflags
)) == -1) {
295 return (ELFSIGN_INVALID_ELFOBJ
);
297 if ((fstat(ess
->es_fd
, &stb
) == -1) || !S_ISREG(stb
.st_mode
)) {
299 return (ELFSIGN_INVALID_ELFOBJ
);
301 if ((ess
->es_pathname
= strdup(filename
)) == NULL
) {
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
));
318 return (ELFSIGN_UNKNOWN
);
321 if (elf_version(EV_CURRENT
) == EV_NONE
) {
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));
330 return (ELFSIGN_INVALID_ELFOBJ
);
333 if (gelf_getehdr(ess
->es_elf
, &elfehdr
) == NULL
) {
334 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
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
);
343 cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
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) {
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
);
367 return (ELFSIGN_SUCCESS
);
371 * elfsign_end - cleanup the ELFsign_t
376 elfsign_end(ELFsign_t ess
)
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",
389 if (ess
->es_fd
!= -1) {
390 (void) close(ess
->es_fd
);
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
);
408 elfcertlib_fini(ess
);
414 * set the certificate path
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
;
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
;
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
459 elfsign_setcallbackctx(ELFsign_t ess
, void *ctx
)
461 ess
->es_callbackctx
= ctx
;
465 * set the signature extraction callback
468 elfsign_setsigvercallback(ELFsign_t ess
,
469 void (*cb
)(void *, void *, size_t, ELFCert_t
))
471 ess
->es_sigvercallback
= cb
;
477 * IN: ess, fsspp, action
481 elfsign_signatures(ELFsign_t ess
,
482 struct filesignatures
**fsspp
,
484 enum ES_ACTION action
)
486 Elf_Scn
*scn
= NULL
, *sig_scn
= NULL
;
488 Elf_Data
*data
= NULL
;
489 const char *elf_section
= SUNW_ELF_SIGNATURE_ID
;
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
);
504 while ((scn
= elf_nextscn(ess
->es_elf
, scn
)) != NULL
) {
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",
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
);
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
,
530 return (ELFSIGN_FAILED
);
533 if (ES_ACTISUPDATE(action
) && (sig_scn
== NULL
)) {
534 size_t old_size
, new_size
;
537 cryptodebug("elfsign_signature: %s not found - creating",
541 * insert section name in .shstrtab
543 if ((scn
= elf_getscn(ess
->es_elf
, ess
->es_shstrndx
)) == 0) {
544 cryptodebug("elf_getscn() failed: %s",
546 return (ELFSIGN_FAILED
);
548 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
549 cryptodebug("gelf_getshdr() failed: %s",
551 return (ELFSIGN_FAILED
);
553 if ((data
= elf_getdata(scn
, data
)) == NULL
) {
554 cryptodebug("elf_getdata() failed: %s",
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
;
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",
582 return (ELFSIGN_FAILED
);
584 if (gelf_getshdr(sig_scn
, &shdr
) == 0) {
585 cryptodebug("gelf_getshdr() failed: %s",
587 return (ELFSIGN_FAILED
);
589 shdr
.sh_name
= old_size
;
590 shdr
.sh_type
= SHT_SUNW_SIGNATURE
;
591 shdr
.sh_flags
= SHF_EXCLUDE
;
596 shdr
.sh_offset
= sig_offset
;
597 shdr
.sh_addralign
= 1;
600 * Flush the changes to the underlying elf32 or elf64
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",
617 return (ELFSIGN_FAILED
);
620 if (sig_scn
== NULL
) {
621 cryptodebug("can't find signature section");
623 return (ELFSIGN_NOTSIGNED
);
625 if ((data
= elf_getdata(sig_scn
, NULL
)) == 0) {
626 cryptodebug("can't get section data for %s",
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
;
638 fsgpnext
= filesig_next(fsgp
);
639 fssize
+= (char *)(fsgpnext
) - (char *)(fsgp
);
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
;
657 data
->d_type
= ELF_T_BYTE
;
658 cryptodebug("elfsign_signature: data->d_size = %d",
660 if (elfsign_adjustoffsets(ess
, sig_scn
, fssize
) !=
662 cryptodebug("can't adjust for revised signature "
664 return (ELFSIGN_FAILED
);
667 *fsspp
= malloc(data
->d_size
);
669 return (ELFSIGN_FAILED
);
670 (void) memcpy(*fsspp
, data
->d_buf
, data
->d_size
);
671 if (elfsign_switch(ess
, *fsspp
, ES_GET
) != ELFSIGN_SUCCESS
) {
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
)
687 uint64_t prev_end
, scn_offset
;
691 ELFsign_status_t retval
= ELFSIGN_FAILED
;
693 struct scninfo
*scni_next
;
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");
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
)
732 if (shdr
.sh_offset
<= scn_offset
)
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 */
741 cryptodebug("elfsign_adjustoffsets: "
742 "can't move allocated section %s",
743 name
? name
: "NULL");
747 * force reading of data to memory image
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");
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
)
772 tmpscnip
->scni_next
= *scnipp
;
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",
786 if (shdr
.sh_offset
>= prev_end
)
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");
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));
811 if (elfehdr
.e_shoff
< prev_end
) {
812 if (ess
->es_ei_class
== ELFCLASS32
)
813 prev_end
= (prev_end
+ ELF32_FSZ_OFF
- 1) &
815 else if (ess
->es_ei_class
== ELFCLASS64
)
816 prev_end
= (prev_end
+ ELF64_FSZ_OFF
- 1) &
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",
829 retval
= ELFSIGN_SUCCESS
;
832 while (scnip
!= NULL
) {
833 tmpscnip
= scnip
->scni_next
;
840 struct filesignatures
*
841 elfsign_insert_dso(ELFsign_t ess
,
842 struct filesignatures
*fssp
,
850 return (filesig_insert_dso(fssp
, ess
->es_version
, dn
, dn_len
,
851 sig
, sig_len
, oid
, oid_len
));
856 elfsign_extract_sig(ELFsign_t ess
,
857 struct filesignatures
*fssp
,
861 struct filesig_extraction fsx
;
862 filesig_vers_t version
;
865 return (FILESIG_UNKNOWN
);
866 if (fssp
->filesig_cnt
!= 1)
867 return (FILESIG_UNKNOWN
);
868 version
= filesig_extract(&fssp
->filesig_sig
, &fsx
);
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
,
877 *sig_len
= fsx
.fsx_sig_len
;
879 version
= FILESIG_UNKNOWN
;
882 version
= FILESIG_UNKNOWN
;
886 if (ess
->es_version
== FILESIG_UNKNOWN
) {
887 ess
->es_version
= 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
)
898 ELFsign_status_t elfstat
;
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 */
911 scn
= elf_getscn(ess
->es_elf
, 0); /* "seek" to start */
913 while ((scn
= elf_nextscn(ess
->es_elf
, scn
)) != 0) {
915 Elf_Data
*data
= NULL
;
917 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
918 elfstat
= ELFSIGN_FAILED
;
922 name
= elf_strptr(ess
->es_elf
, ess
->es_shstrndx
,
923 (size_t)shdr
.sh_name
);
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
);
937 } else if (!(shdr
.sh_flags
& SHF_ALLOC
)) {
939 * select only memory resident sections
941 cryptodebug("elfsign_hash: skipping %s", name
);
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",
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
;
968 SHA1Final(hash
, &ctx
);
969 *hash_len
= SHA1_DIGEST_LENGTH
;
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
);
980 elfstat
= ELFSIGN_SUCCESS
;
986 * elfsign_hash - return the hash of the ELF sections affecting execution.
989 * OUT: hash, hash_len
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.
1002 * OUT: hash, hash_len
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.
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
;
1026 struct filesig_extraction fsx
;
1027 uchar_t hash
[SIG_MAX_LENGTH
];
1029 ELFCert_t cert
= NULL
;
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
));
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
;
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
:
1069 ret
= ELFSIGN_FAILED
;
1073 cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
1075 cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
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
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
);
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");
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) {
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
;
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
);
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");
1165 elfcertlib_releasecert(ess
, cert
);
1168 if (ret
== ELFSIGN_FAILED
&& nocert
)
1169 ret
= ELFSIGN_INVALID_CERTPATH
;
1175 elfsign_switch_uint32(uint32_t i
)
1177 return (((i
& 0xff) << 24) | ((i
& 0xff00) << 8) |
1178 ((i
>> 8) & 0xff00) | ((i
>> 24) & 0xff));
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
)
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
);
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
);
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
);
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
1256 elfsign_buffer_len(ELFsign_t ess
, size_t *ip
, uchar_t
*cp
,
1257 enum ES_ACTION action
)
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
);
1269 /* put integer into buffer */
1271 if (!ess
->es_same_endian
) {
1272 tmp
= elfsign_switch_uint32(tmp
);
1274 (void) memcpy(cp
, &tmp
, sizeof (tmp
));
1279 elfsign_strerror(ELFsign_status_t elferror
)
1281 char const *msg
= NULL
;
1284 case ELFSIGN_SUCCESS
:
1285 msg
= gettext("sign or verify of ELF object succeeded");
1287 case ELFSIGN_FAILED
:
1288 msg
= gettext("sign or verify of ELF object failed");
1290 case ELFSIGN_NOTSIGNED
:
1291 msg
= gettext("ELF object not signed");
1293 case ELFSIGN_INVALID_CERTPATH
:
1294 msg
= gettext("cannot access certificate");
1296 case ELFSIGN_INVALID_ELFOBJ
:
1297 msg
= gettext("unable to open as an ELF object");
1299 case ELFSIGN_UNKNOWN
:
1301 msg
= gettext("Unknown error");
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
));
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
;
1334 return (*esipp
!= NULL
);
1338 elfsign_sig_info_free(struct ELFsign_sig_info
*esip
)
1341 free(esip
->esi_signer
);