From 2bd3976ed01e76496a509ecd3443559f2be6f60c Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Mon, 11 May 2015 11:39:04 +0200 Subject: [PATCH] Add iOS-specific fips_algvs application. Reviewed-by: Dr. Stephen Henson --- iOS/Makefile | 76 ++ iOS/fips_algvs.app/Entitlements.plist | 8 + iOS/fips_algvs.app/Info.plist | 24 + iOS/fips_algvs.app/ResourceRules.plist | 25 + iOS/fopen.m | 93 +++ iOS/incore_macho.c | 1016 ++++++++++++++++++++++++ test/fips_algvs.c | 10 + 7 files changed, 1252 insertions(+) create mode 100644 iOS/Makefile create mode 100644 iOS/fips_algvs.app/Entitlements.plist create mode 100644 iOS/fips_algvs.app/Info.plist create mode 100644 iOS/fips_algvs.app/ResourceRules.plist create mode 100644 iOS/fopen.m create mode 100644 iOS/incore_macho.c diff --git a/iOS/Makefile b/iOS/Makefile new file mode 100644 index 0000000000..db26da6406 --- /dev/null +++ b/iOS/Makefile @@ -0,0 +1,76 @@ +# +# OpenSSL/iOS/Makefile +# + +DIR= iOS +TOP= .. +CC= cc +INCLUDES= -I$(TOP) -I$(TOP)/include +CFLAG= -g -static +MAKEFILE= Makefile +PERL= perl +RM= rm -f + +EXE=incore_macho + +CFLAGS= $(INCLUDES) $(CFLAG) + +top: + @$(MAKE) -f $(TOP)/Makefile reflect THIS=exe + +exe: fips_algvs.app/fips_algvs + +incore_macho: incore_macho.c $(TOP)/crypto/sha/sha1dgst.c + $(HOSTCC) $(HOSTCFLAGS) -I$(TOP)/include -I$(TOP)/crypto -o $@ incore_macho.c $(TOP)/crypto/sha/sha1dgst.c + +fips_algvs.app/fips_algvs: $(TOP)/test/fips_algvs.c $(TOP)/fips/fipscanister.o fopen.m incore_macho + FIPS_SIG=./incore_macho \ + $(TOP)/fips/fipsld $(CFLAGS) -I$(TOP)/fips -o $@ \ + $(TOP)/test/fips_algvs.c $(TOP)/fips/fipscanister.o \ + fopen.m -framework Foundation || rm $@ + codesign -f -s "iPhone Developer" --entitlements fips_algvs.app/Entitlements.plist fips_algvs.app || rm $@ + +install: + @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile... + @set -e; for i in $(EXE); \ + do \ + (echo installing $$i; \ + cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new; \ + chmod 755 $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new; \ + mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i ); \ + done; + @set -e; for i in $(SCRIPTS); \ + do \ + (echo installing $$i; \ + cp $$i $(INSTALL_PREFIX)$(OPENSSLDIR)/misc/$$i.new; \ + chmod 755 $(INSTALL_PREFIX)$(OPENSSLDIR)/misc/$$i.new; \ + mv -f $(INSTALL_PREFIX)$(OPENSSLDIR)/misc/$$i.new $(INSTALL_PREFIX)$(OPENSSLDIR)/misc/$$i ); \ + done + +tags: + ctags $(SRC) + +tests: + +links: + +lint: + lint -DLINT $(INCLUDES) $(SRC)>fluff + +depend: + @if [ -z "$(THIS)" ]; then \ + $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; \ + else \ + $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(SRC); \ + fi + +dclean: + $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new + mv -f Makefile.new $(MAKEFILE) + +clean: + rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff $(EXE) + rm -f fips_algvs.app/fips_algvs + +# DO NOT DELETE THIS LINE -- make depend depends on it. + diff --git a/iOS/fips_algvs.app/Entitlements.plist b/iOS/fips_algvs.app/Entitlements.plist new file mode 100644 index 0000000000..929c4e96d2 --- /dev/null +++ b/iOS/fips_algvs.app/Entitlements.plist @@ -0,0 +1,8 @@ + + + + + get-task-allow + + + \ No newline at end of file diff --git a/iOS/fips_algvs.app/Info.plist b/iOS/fips_algvs.app/Info.plist new file mode 100644 index 0000000000..3fd8fb4290 --- /dev/null +++ b/iOS/fips_algvs.app/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleName + fips_algvs + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleExecutable + fips_algvs + CFBundleIdentifier + fips_algvs + CFBundleResourceSpecification + ResourceRules.plist + LSRequiresIPhoneOS + + CFBundleDisplayName + fips_algvs + CFBundleVersion + 1.0 + + diff --git a/iOS/fips_algvs.app/ResourceRules.plist b/iOS/fips_algvs.app/ResourceRules.plist new file mode 100644 index 0000000000..e7ec329dcc --- /dev/null +++ b/iOS/fips_algvs.app/ResourceRules.plist @@ -0,0 +1,25 @@ + + + + + rules + + .* + + Info.plist + + omit + + weight + 10 + + ResourceRules.plist + + omit + + weight + 100 + + + + diff --git a/iOS/fopen.m b/iOS/fopen.m new file mode 100644 index 0000000000..8d2e790845 --- /dev/null +++ b/iOS/fopen.m @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +static FILE *(*libc_fopen)(const char *, const char *) = NULL; + +__attribute__((constructor)) +static void pre_main(void) +{ + /* + * Pull reference to fopen(3) from libc. + */ + void *handle = dlopen("libSystem.B.dylib",RTLD_LAZY); + + if (handle) { + libc_fopen = dlsym(handle,"fopen"); + dlclose(handle); + } + + /* + * Change to Documents directory. + */ + NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + + NSFileManager *filemgr = [NSFileManager defaultManager]; + [filemgr changeCurrentDirectoryPath: docs]; + [filemgr release]; +} + +char *mkdirhier(char *path) +{ + char *slash; + struct stat buf; + + if (path[0]=='.' && path[1]=='/') path+=2; + + if ((slash = strrchr(path,'/'))) { + *slash = '\0'; + if (stat(path,&buf)==0) { + *slash = '/'; + return NULL; + } + (void)mkdirhier(path); + mkdir (path,0777); + *slash = '/'; + } + + return slash; +} +/* + * Replacement fopen(3) + */ +FILE *fopen(const char *filename, const char *mode) +{ + FILE *ret; + + if ((ret = (*libc_fopen)(filename,mode)) == NULL) { + /* + * If file is not present in Documents directory, try from Bundle. + */ + NSString *nsspath = [NSString stringWithFormat:@"%@/%s", + [[NSBundle mainBundle] bundlePath], + filename]; + + if ((ret = (*libc_fopen)([nsspath cStringUsingEncoding:NSUTF8StringEncoding],mode)) == NULL && + mode[0]=='w' && + ((filename[0]!='.' && filename[0]!='/') || + (filename[0]=='.' && filename[1]=='/')) ) { + /* + * If not present in Bundle, create directory in Documents + */ + char *path = strdup(filename), *slash; + static int once = 1; + + if ((slash = mkdirhier(path)) && once) { + /* + * For some reason iOS truncates first created file + * upon program exit, so we create one preemptively... + */ + once = 0; + strcpy(slash,"/.0"); + creat(path,0444); + } + free(path); + ret = (*libc_fopen)(filename,mode); + } + } + + return ret; +} diff --git a/iOS/incore_macho.c b/iOS/incore_macho.c new file mode 100644 index 0000000000..8842764cb0 --- /dev/null +++ b/iOS/incore_macho.c @@ -0,0 +1,1016 @@ +/* incore_macho.c */ +/* ==================================================================== + * Copyright (c) 2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* ==================================================================== + * Copyright 2011 Thursby Software Systems, Inc. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Thursby Software Systems, Inc and is licensed pursuant to the OpenSSL + * open source license. + * + * The Contribution, originally written by Paul W. Nelson of + * Thursby Software Systems, Inc, consists of the fingerprint calculation + * required for the FIPS140 integrity check. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Thursby that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, THURSBY + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CPU_SUBRTPE_V7F +# define CPU_SUBRTPE_V7F ((cpu_subtype_t) 10) +#endif +/* iPhone 5 and iPad 4 (A6 Processors) */ +#ifndef CPU_SUBTYPE_ARM_V7S +# define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11) +#endif +#ifndef CPU_SUBTYPE_ARM_V7K +# define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12) +#endif +#ifndef CPU_SUBTYPE_ARM_V8 +# define CPU_SUBTYPE_ARM_V8 ((cpu_subtype_t) 13) +#endif + +#ifndef CPU_TYPE_ARM64 +# define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif + +static int gVerbosity = 0; + +static void hexdump(const unsigned char *buf,size_t len, + unsigned long address,FILE* fp) +{ + unsigned long addr; + int i; + + addr = 0; + while(addrflags; + memcpy( sec->sectname, pSec->sectname, 16 ); + memcpy( sec->segname, pSec->segname, 16 ); + sec->addr = pSec->addr; + sec->size = pSec->size; + sec->offset = pSec->offset; + sec->align = pSec->align; + sec->reloff = pSec->reloff; + sec->nreloc = pSec->nreloc; + sec->flags = pSec->flags; + rval = pCommand + sizeof(struct section_64); + } + else + { + struct section* pSec = (struct section*)pCommand; + flags = pSec->flags; + memcpy( sec->sectname, pSec->sectname, 16 ); + memcpy( sec->segname, pSec->segname, 16 ); + sec->addr = pSec->addr; + sec->size = pSec->size; + sec->offset = pSec->offset; + sec->align = pSec->align; + sec->reloff = pSec->reloff; + sec->nreloc = pSec->nreloc; + sec->flags = pSec->flags; + rval = pCommand + sizeof(struct section); + } + if( gVerbosity > 2 ) + fprintf(stderr, " flags=%x\n", flags); + sec->segment = segment; + sec->_next = NULL; + if( macho->sec_head ) + macho->sec_tail->_next = sec; + else + macho->sec_head = sec; + macho->sec_tail = sec; + return rval; +} + +static section_t *lookup_section(macho_file_t* macho, uint32_t nsect) +{ + section_t *rval = macho->sec_head; + + if(nsect == 0) return NULL; + + while( rval != NULL && --nsect > 0 ) + rval = rval->_next; + return rval; +} + +static void *add_segment( macho_file_t *macho, void *pCommand, uint8_t is64bit ) +{ + void *rval = 0; + segment_t *seg = (segment_t *)calloc(1, sizeof(segment_t)); + + if(!seg) + return 0; + if(is64bit) + { + struct segment_command_64 *pSeg = (struct segment_command_64*)pCommand; + + memcpy( seg->segname, pSeg->segname, 16 ); + seg->vmaddr = pSeg->vmaddr; + seg->vmsize = pSeg->vmsize; + seg->fileoff = pSeg->fileoff; + seg->filesize = pSeg->filesize; + seg->maxprot = pSeg->maxprot; + seg->initprot = pSeg->initprot; + seg->nsects = pSeg->nsects; + seg->flags = pSeg->flags; + rval = pCommand + sizeof(struct segment_command_64); + } else { + struct segment_command *pSeg = (struct segment_command*)pCommand; + + memcpy( seg->segname, pSeg->segname, 16 ); + seg->vmaddr = pSeg->vmaddr; + seg->vmsize = pSeg->vmsize; + seg->fileoff = pSeg->fileoff; + seg->filesize = pSeg->filesize; + seg->maxprot = pSeg->maxprot; + seg->initprot = pSeg->initprot; + seg->nsects = pSeg->nsects; + seg->flags = pSeg->flags; + rval = pCommand + sizeof(struct segment_command); + } + seg->_next = NULL; + seg->mapped = macho->mapped + seg->fileoff; + + if( macho->seg_head ) + macho->seg_tail->_next = seg; + else + macho->seg_head = seg; + macho->seg_tail = seg; + + if( gVerbosity > 2 ) + fprintf(stderr, "Segment %s: flags=%x\n", seg->segname, seg->flags ); + + unsigned int ii; + for( ii=0; iinsects; ii++ ) + { + rval = add_section(macho, rval, is64bit, seg); + } + return rval; +} + +static const char *type_str(uint8_t n_type) +{ + static char result[16] = {}; + int idx = 0; + uint8_t stab; + + memset(result, 0, sizeof(result)); + if( n_type & N_PEXT ) + result[idx++] = 'P'; + if( n_type & N_EXT ) + result[idx++] = 'E'; + if( idx > 0 ) + result[idx++] = ':'; + switch( n_type & N_TYPE ) + { + case N_UNDF: result[idx++] = 'U'; break; + case N_ABS: result[idx++] = 'A'; break; + case N_PBUD: result[idx++] = 'P'; break; + case N_SECT: result[idx++] = 'S'; break; + case N_INDR: result[idx++] = 'I'; break; + default: result[idx++] = '*'; break; + } + stab = n_type & N_STAB; + if( stab ) + { + result[idx++] = ':'; + result[idx++] = '0'+(stab >> 5); + } + result[idx++] = 0; + return result; +} + +static symtab_entry_t *lookup_entry_by_name( macho_file_t *macho, + const char *name) +{ + symtab_entry_t *entry; + + for( entry = macho->sym_head; entry; entry = entry->_next ) + { + if(strcmp(entry->n_symbol,name)==0 && (entry->n_type & N_STAB)==0 ) + { + if( entry->section == NULL ) + { + entry->section = lookup_section( macho, entry->n_sect ); + if( entry->section ) + { + section_t* sec = entry->section; + segment_t* seg = sec->segment; + uint64_t offset = entry->n_value - seg->vmaddr; + + entry->mapped = seg->mapped+offset; + } + else + entry = 0; + } + break; + } + } + return entry; +} + +static void check_symtab(macho_file_t *macho,void *pCommand,uint8_t is64bit ) +{ + + struct symtab_command *pSym = (struct symtab_command *)pCommand; + void *pS = macho->mapped + pSym->symoff; + unsigned int ii = 0; + + /* collect symbols */ + for( ii=0; iinsyms; ii++ ) + { + struct nlist *pnlist=(struct nlist*)pS; + symtab_entry_t *entry=(symtab_entry_t*)calloc(1,sizeof(symtab_entry_t)); + + if(!entry) + { + fprintf(stderr, "out of memory!\n"); + _exit(1); + } + entry->n_strx = pnlist->n_un.n_strx; + entry->n_type = pnlist->n_type; + entry->n_sect = pnlist->n_sect; + entry->n_desc = pnlist->n_desc; + entry->section = NULL; + if(is64bit) + { + struct nlist_64 *pnlist64 = (struct nlist_64*)pS; + + entry->n_value = pnlist64->n_value; + pS += sizeof(struct nlist_64); + } + else + { + entry->n_value = pnlist->n_value; + pS += sizeof(struct nlist); + } + entry->n_symbol=(const char *)macho->mapped+pSym->stroff+entry->n_strx; + entry->_next = NULL; + if( macho->sym_head ) + macho->sym_tail->_next = entry; + else + macho->sym_head = entry; + macho->sym_tail = entry; + } + if( gVerbosity > 2 ) + { + /* dump info */ + symtab_entry_t* entry; + + for( entry = macho->sym_head; entry; entry=entry->_next ) + { + /* only do non-debug symbols */ + if( (entry->n_type & N_STAB) == 0 ) + fprintf(stderr, "%32.32s %18llx type=%s, sect=%d\n", + entry->n_symbol, entry->n_value, + type_str(entry->n_type), entry->n_sect); + } + } +} + +static int load_architecture( macho_file_t* inFile ) +{ + /* check the header */ + unsigned int ii; + void * pCurrent = inFile->mapped; + struct mach_header* header = (struct mach_header*)pCurrent; + + if( header->magic != MH_MAGIC && header->magic != MH_MAGIC_64 ) + { + fprintf(stderr, "%s is not a mach-o file\n", inFile->filename); + return -1; + } + else if( header->filetype == MH_BUNDLE ) + { + fprintf(stderr, "%s is not a mach-o executable file (filetype MH_BUNDLE, should be MH_EXECUTE or MH_DYLIB)\n", inFile->filename); + return -1; + } + else if( header->filetype == MH_DYLINKER ) + { + fprintf(stderr, "%s is not a mach-o executable file (filetype MH_DYLINKER, should be MH_EXECUTE or MH_DYLIB)\n", inFile->filename); + return -1; + } + else if( !(header->filetype == MH_EXECUTE || header->filetype == MH_DYLIB) ) + { + fprintf(stderr, "%s is not a mach-o executable file (filetype %d, should be MH_EXECUTE or MH_DYLIB)\n", inFile->filename, header->filetype); + return -1; + } + + if( gVerbosity > 1 ) + fprintf(stderr, "loading %s(%s)\n", inFile->filename, cputype(header->cputype, header->cpusubtype)); + + inFile->cpu_type = header->cputype; + inFile->cpu_subtype = header->cpusubtype; + + if( header->magic == MH_MAGIC ) + pCurrent += sizeof( struct mach_header ); + else if( header->magic == MH_MAGIC_64 ) + pCurrent += sizeof( struct mach_header_64 ); + for( ii=0; iincmds; ii++ ) + { + struct load_command* command = (struct load_command*)pCurrent; + const char * lc_name; + + switch( command->cmd ) + { + case LC_SEGMENT: + { + lc_name = "LC_SEGMENT"; + add_segment(inFile, pCurrent, header->magic == MH_MAGIC_64); + break; + } + case LC_SYMTAB: + { + lc_name = "LC_SYMTAB"; + check_symtab(inFile, pCurrent, header->magic == MH_MAGIC_64 ); + break; + } + case LC_SYMSEG: lc_name = "LC_SYMSEG"; break; + case LC_THREAD: lc_name = "LC_THREAD"; break; + case LC_UNIXTHREAD: lc_name = "LC_UNIXTHREAD"; break; + case LC_LOADFVMLIB: lc_name = "LC_LOADFVMLIB"; break; + case LC_IDFVMLIB: lc_name = "LC_IDFVMLIB"; break; + case LC_IDENT: lc_name = "LC_IDENT"; break; + case LC_FVMFILE: lc_name = "LC_FVMFILE"; break; + case LC_PREPAGE: lc_name = "LC_PREPAGE"; break; + case LC_DYSYMTAB: lc_name = "LC_DYSYMTAB"; break; + case LC_LOAD_DYLIB: lc_name = "LC_LOAD_DYLIB"; break; + case LC_ID_DYLIB: lc_name = "LC_ID_DYLIB"; break; + case LC_LOAD_DYLINKER: lc_name = "LC_LOAD_DYLINKER"; break; + case LC_ID_DYLINKER: lc_name = "LC_ID_DYLINKER"; break; + case LC_PREBOUND_DYLIB: lc_name = "LC_PREBOUND_DYLIB"; break; + case LC_ROUTINES: lc_name = "LC_ROUTINES"; break; + case LC_SUB_FRAMEWORK: lc_name = "LC_SUB_FRAMEWORK"; break; + case LC_SUB_UMBRELLA: lc_name = "LC_SUB_UMBRELLA"; break; + case LC_SUB_CLIENT: lc_name = "LC_SUB_CLIENT"; break; + case LC_SUB_LIBRARY: lc_name = "LC_SUB_LIBRARY"; break; + case LC_TWOLEVEL_HINTS: lc_name = "LC_TWOLEVEL_HINTS"; break; + case LC_PREBIND_CKSUM: lc_name = "LC_PREBIND_CKSUM"; break; + case LC_LOAD_WEAK_DYLIB: lc_name = "LC_LOAD_WEAK_DYLIB"; break; + case LC_SEGMENT_64: + { + lc_name = "LC_SEGMENT_64"; + add_segment(inFile, pCurrent, TRUE); + break; + } + case LC_ROUTINES_64: lc_name = "LC_ROUTINES_64"; break; + case LC_UUID: lc_name = "LC_UUID"; break; + case LC_RPATH: lc_name = "LC_RPATH"; break; + case LC_CODE_SIGNATURE: lc_name = "LC_CODE_SIGNATURE"; break; + case LC_SEGMENT_SPLIT_INFO: + lc_name = "LC_SEGMENT_SPLIT_INFO"; break; + case LC_REEXPORT_DYLIB: lc_name = "LC_REEXPORT_DYLIB"; break; + case LC_LAZY_LOAD_DYLIB: lc_name = "LC_LAZY_LOAD_DYLIB"; break; + case LC_ENCRYPTION_INFO: lc_name = "LC_ENCRYPTION_INFO"; break; + case LC_DYLD_INFO: lc_name = "LC_DYLD_INFO"; break; + case LC_DYLD_INFO_ONLY: lc_name = "LC_DYLD_INFO_ONLY"; break; + case LC_LOAD_UPWARD_DYLIB: lc_name = "LC_LOAD_UPWARD_DYLIB"; break; + case LC_VERSION_MIN_MACOSX: + lc_name = "LC_VERSION_MIN_MACOSX"; break; + case LC_VERSION_MIN_IPHONEOS: + lc_name = "LC_VERSION_MIN_IPHONEOS"; break; + case LC_FUNCTION_STARTS: lc_name = "LC_FUNCTION_STARTS"; break; + case LC_DYLD_ENVIRONMENT: lc_name = "LC_DYLD_ENVIRONMENT"; break; + default: lc_name=NULL; break; + } + if( gVerbosity > 1 ) + { + if(lc_name) + fprintf(stderr,"command %s: size=%d\n",lc_name, + command->cmdsize ); + else + fprintf(stderr,"command %x, size=%d\n",command->cmd, + command->cmdsize); + } + pCurrent += command->cmdsize; + } + return 0; +} + +#define HOSTORDER_VALUE(val) (isBigEndian ? OSSwapBigToHostInt32(val) : (val)) + +static macho_file_t *load_file(macho_file_t *inFile) +{ + macho_file_t *rval = NULL; + void *pCurrent = inFile->mapped; + struct fat_header *fat = (struct fat_header *)pCurrent; + + if( fat->magic==FAT_MAGIC || fat->magic==FAT_CIGAM ) + { + int isBigEndian = fat->magic == FAT_CIGAM; + unsigned int ii = 0; + struct fat_arch *pArch = NULL; + uint32_t nfat_arch = 0; + + pCurrent += sizeof(struct fat_header); + pArch = pCurrent; + nfat_arch = HOSTORDER_VALUE(fat->nfat_arch); + for( ii=0; iifilename = strdup(inFile->filename); + archfile->mapped = inFile->mapped + + HOSTORDER_VALUE(pArch->offset); + archfile->size = HOSTORDER_VALUE(pArch->size); + archfile->align = HOSTORDER_VALUE(pArch->align); + archfile->isBigEndian = isBigEndian; + archfile->cpu_type = HOSTORDER_VALUE(pArch->cputype); + archfile->cpu_subtype = HOSTORDER_VALUE(pArch->cpusubtype); + if( load_architecture(archfile) == 0 ) + { + archfile->next = rval; + rval = archfile; + } + } + else + return NULL; /* no memory */ + pArch++; + } + } + else + { + struct mach_header* header = (struct mach_header*)pCurrent; + + if( header->magic != MH_MAGIC && header->magic != MH_MAGIC_64 ) + { + fprintf(stderr, "%s is not a mach-o file\n", inFile->filename); + } + else if( header->filetype == MH_BUNDLE ) + { + fprintf(stderr, "%s is not a mach-o executable file " + "(filetype MH_BUNDLE, should be MH_EXECUTE or MH_DYLIB)\n", inFile->filename); + } + else if( header->filetype == MH_DYLINKER ) + { + fprintf(stderr, "%s is not a mach-o executable file " + "(filetype MH_DYLINKER, should be MH_EXECUTE or MH_DYLIB)\n", inFile->filename); + } + else if( !(header->filetype == MH_EXECUTE || header->filetype == MH_DYLIB) ) + { + fprintf(stderr, "%s is not a mach-o executable file " + "(filetype %d should be MH_EXECUTE or MH_DYLIB)\n", + inFile->filename, header->filetype ); + } + if( load_architecture(inFile) == 0 ) + { + inFile->next = 0; + rval = inFile; + } + } + return rval; +} + +#define FIPS_SIGNATURE_SIZE 20 +#define FIPS_FINGERPRINT_SIZE 40 + +static void debug_symbol( symtab_entry_t* sym ) +{ + if( gVerbosity > 1 ) + { + section_t* sec = sym->section; + segment_t* seg = sec->segment; + fprintf(stderr, "%-40.40s: %llx sect=%s, segment=%s prot=(%x->%x)\n", + sym->n_symbol, sym->n_value, sec->sectname, + seg->segname, seg->initprot, seg->maxprot ); + } +} + +/* + * Minimalistic HMAC from fips_standalone_sha1.c + */ +static void hmac_init(SHA_CTX *md_ctx,SHA_CTX *o_ctx, + const char *key) + { + size_t len=strlen(key); + int i; + unsigned char keymd[HMAC_MAX_MD_CBLOCK]; + unsigned char pad[HMAC_MAX_MD_CBLOCK]; + + if (len > SHA_CBLOCK) + { + SHA1_Init(md_ctx); + SHA1_Update(md_ctx,key,len); + SHA1_Final(keymd,md_ctx); + len=20; + } + else + memcpy(keymd,key,len); + memset(&keymd[len],'\0',HMAC_MAX_MD_CBLOCK-len); + + for(i=0 ; i < HMAC_MAX_MD_CBLOCK ; i++) + pad[i]=0x36^keymd[i]; + SHA1_Init(md_ctx); + SHA1_Update(md_ctx,pad,SHA_CBLOCK); + + for(i=0 ; i < HMAC_MAX_MD_CBLOCK ; i++) + pad[i]=0x5c^keymd[i]; + SHA1_Init(o_ctx); + SHA1_Update(o_ctx,pad,SHA_CBLOCK); + } + +static void hmac_final(unsigned char *md,SHA_CTX *md_ctx,SHA_CTX *o_ctx) + { + unsigned char buf[20]; + + SHA1_Final(buf,md_ctx); + SHA1_Update(o_ctx,buf,sizeof buf); + SHA1_Final(md,o_ctx); + } + +static int fingerprint(macho_file_t* inFile, int addFingerprint) +{ + int rval = 0; + unsigned char signature[FIPS_SIGNATURE_SIZE]; + char signature_string[FIPS_FINGERPRINT_SIZE+1]; + unsigned int len = sizeof(signature); + const char *fingerprint = NULL; + int ii = 0; + +#define LOOKUP_SYMBOL( symname, prot ) \ + symtab_entry_t *symname = \ + lookup_entry_by_name( inFile, "_" #symname ); \ + if( ! symname ) { \ + fprintf(stderr, "%s: Not a FIPS executable (" \ + #symname " not found)\n", inFile->filename ); \ + return -1;\ + } \ + if( (symname->section->segment->initprot & \ + (PROT_READ|PROT_WRITE|PROT_EXEC)) != (prot) ) { \ + fprintf(stderr, #symname \ + " segment has the wrong protection.\n"); \ + debug_symbol(symname);return -1;\ + } + + LOOKUP_SYMBOL( FIPS_rodata_start, PROT_READ | PROT_EXEC ); + LOOKUP_SYMBOL( FIPS_rodata_end, PROT_READ | PROT_EXEC ); + LOOKUP_SYMBOL( FIPS_text_startX, PROT_READ | PROT_EXEC ); + LOOKUP_SYMBOL( FIPS_text_endX, PROT_READ | PROT_EXEC ); + LOOKUP_SYMBOL( FIPS_signature, PROT_WRITE | PROT_READ ); + LOOKUP_SYMBOL( FINGERPRINT_ascii_value, PROT_READ | PROT_EXEC ); + + if( gVerbosity > 1 ) + { + debug_symbol( FIPS_rodata_start ); + debug_symbol( FIPS_rodata_end ); + debug_symbol( FIPS_text_startX ); + debug_symbol( FIPS_text_endX ); + debug_symbol( FIPS_signature ); + debug_symbol( FINGERPRINT_ascii_value ); + + fingerprint = (const char *)FINGERPRINT_ascii_value->mapped; + fprintf(stderr, "fingerprint: "); + for(ii=0; ii<40; ii++ ) + { + if( fingerprint[ii] == 0 ) + break; + putc(fingerprint[ii], stderr); + } + putc('\n', stderr); + } + + /* check for the prefix ? character */ + { + const unsigned char * p1 = FIPS_text_startX->mapped; + const unsigned char * p2 = FIPS_text_endX->mapped; + const unsigned char * p3 = FIPS_rodata_start->mapped; + const unsigned char * p4 = FIPS_rodata_end->mapped; + static const char FIPS_hmac_key[]="etaonrishdlcupfm"; + SHA_CTX md_ctx,o_ctx; + + hmac_init(&md_ctx,&o_ctx,FIPS_hmac_key); + + if (p1<=p3 && p2>=p3) + p3=p1, p4=p2>p4?p2:p4, p1=NULL, p2=NULL; + else if (p3<=p1 && p4>=p1) + p3=p3, p4=p2>p4?p2:p4, p1=NULL, p2=NULL; + + if (p1) { + + SHA1_Update(&md_ctx,p1,(size_t)p2-(size_t)p1); + } + if (FIPS_signature->mapped>=p3 && FIPS_signature->mappedmapped+FIPS_SIGNATURE_SIZE; + if (p3mapped; + inFile->fingerprint_original = strndup(fingerprint,FIPS_FINGERPRINT_SIZE); + inFile->fingerprint_computed = strdup(signature_string); + + if( addFingerprint ) + { + void *fp_page = NULL; + void *fp_end = NULL; + + if(strcmp(fingerprint,"?have to make sure this string is unique")!=0) + { + if (memcmp((char*)fingerprint, signature_string, FIPS_FINGERPRINT_SIZE)!=0) + { + fprintf(stderr, + "%s(%s) original fingerprint incorrect: %s\n", + inFile->filename, + cputype(inFile->cpu_type, inFile->cpu_subtype), + fingerprint); + } + } + + fp_page = (void*)((uintptr_t)fingerprint & ~PAGE_MASK); + fp_end = (void*)((uintptr_t)(fingerprint+(PAGE_SIZE*2)) & ~PAGE_MASK); + if( mprotect( fp_page, fp_end-fp_page, PROT_READ|PROT_WRITE ) ) + { + perror("Can't write the fingerprint - mprotect failed"); + fprintf(stderr, "fp_page=%p, fp_end=%p, len=%ld\n", + fp_page, fp_end, (size_t)(fp_end-fp_page)); + rval = 1; + } + else + { + memcpy((char*)fingerprint, signature_string, FIPS_FINGERPRINT_SIZE); + if( msync(fp_page, (fp_end-fp_page), 0) ) + perror("msync failed"); + } + if( gVerbosity > 0 ) + fprintf(stderr, "%s(%s) fingerprint: %s\n", inFile->filename, + cputype(inFile->cpu_type,inFile->cpu_subtype), + signature_string); + } + if( *fingerprint == '?' ) + { + printf("%s(%s) has no fingerprint.\n", inFile->filename, + cputype(inFile->cpu_type, inFile->cpu_subtype)); + rval = 2; + } + else if( strncmp( fingerprint, signature_string, FIPS_FINGERPRINT_SIZE) == 0 ) + { + if( ! addFingerprint ) + printf("%s(%s) fingerprint is correct: %s\n", inFile->filename, + cputype(inFile->cpu_type, inFile->cpu_subtype), + signature_string); + } + else + { + printf("%s(%s) fingerprint %.40s is not correct\n", inFile->filename, + cputype(inFile->cpu_type,inFile->cpu_subtype), fingerprint); + printf("calculated: %s\n", signature_string); + rval = -1; + } + return rval; +} + +static int make_fingerprint( const char * inApp, int addFingerprint ) +{ + int rval = 1; + int appfd = -1; + if( addFingerprint ) + appfd = open( inApp, O_RDWR ); + if( appfd < 0 ) + { + if( addFingerprint ) + fprintf(stderr, "Can't modify %s. Verifying only.\n", inApp); + addFingerprint = 0; + appfd = open( inApp, O_RDONLY ); + } + if( appfd >= 0 ) + { + struct stat stbuf; + fstat(appfd, &stbuf); + void * pApp = mmap(0, (size_t)stbuf.st_size, PROT_READ, + MAP_SHARED, appfd, (off_t)0); + if( pApp == MAP_FAILED ) + { + perror(inApp); + } + else + { + macho_file_t theFile; + macho_file_t* architectures; + macho_file_t* pArchitecture; + + memset( &theFile, 0, sizeof(theFile) ); + theFile.filename = inApp; + theFile.mapped = pApp; + architectures = load_file(&theFile); + for( pArchitecture = architectures; pArchitecture; + pArchitecture = pArchitecture->next ) + { + rval = fingerprint(pArchitecture, addFingerprint); + if( rval && addFingerprint ) + { + printf("Failure\n"); + break; + } + } + if((rval==0) && addFingerprint) + { + printf("Fingerprint Stored\n"); + } + munmap(pApp, (size_t)stbuf.st_size); + } + close(appfd); + } + else + { + fprintf(stderr, "Can't open %s\n", inApp ); + } + return rval; +} + +static void print_usage(const char * prog) +{ + fprintf(stderr, "usage:\n\t%s [--debug] [--quiet] [-exe|-dso|-dylib] executable\n", prog); + _exit(1); +} + +int main (int argc, const char * argv[]) +{ + const char * pname = argv[0]; + const char * filename = NULL; + int addFingerprint = 1; + const char * verbose_env = getenv("FIPS_SIG_VERBOSE"); + + if( verbose_env ) + gVerbosity = atoi(verbose_env); + + if( gVerbosity < 0 ) + gVerbosity = 1; + + while( --argc ) + { + ++argv; + if( strcmp(*argv,"-exe")==0 || strcmp(*argv,"--exe")==0 || + strcmp(*argv,"-dso")==0 || strcmp(*argv,"--dso")==0 || + strcmp(*argv,"-dylib")==0 || strcmp(*argv,"--dylib")==0 || + strcmp(*argv,"--verify")==0 ) + { + if(strcmp(*argv,"--verify")==0) + addFingerprint=0; + + if( argc > 0 ) + { + filename = *++argv; + argc--; + } + } + else if(strcmp(*argv,"-d")==0 || strcmp(*argv,"-debug")==0 || strcmp(*argv,"--debug")==0) + { + if( gVerbosity < 2 ) + gVerbosity = 2; + else + gVerbosity++; + } + else if(strcmp(*argv,"-q")==0 || strcmp(*argv,"-quiet")==0 || strcmp(*argv,"--quiet")==0) + gVerbosity = 0; + else if(strncmp(*argv,"-",1)!=0) { + filename = *argv; + } + } + + if( !filename ) + { + print_usage(pname); + return 1; + } + + if( access(filename, R_OK) ) + { + fprintf(stderr, "Can't access %s\n", filename); + return 1; + } + + return make_fingerprint( filename, addFingerprint ); +} + diff --git a/test/fips_algvs.c b/test/fips_algvs.c index ed0350720a..d47fb27dcc 100644 --- a/test/fips_algvs.c +++ b/test/fips_algvs.c @@ -265,6 +265,16 @@ int main(int argc, char **argv) SysInit(); #endif +#if defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) + if (*args && !strcmp(*args, "-noaccel")) + { + extern unsigned int OPENSSL_armcap_P; + + OPENSSL_armcap_P=0; + args++; + argc--; + } +#endif if (*args && *args[0] != '-') { rv = run_prg(argc - 1, args); -- 2.25.1