fips_premain.c revision 194206
1/* ==================================================================== 2 * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution 3 * and usage in source and binary forms are granted according to the 4 * OpenSSL license. 5 */ 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#if defined(__unix) || defined(__unix__) 11#include <unistd.h> 12#endif 13 14#ifndef FINGERPRINT_PREMAIN_DSO_LOAD 15 16#if defined(__GNUC__) && __GNUC__>=2 17 void FINGERPRINT_premain(void) __attribute__((constructor)); 18 /* Most commonly this results in pointer to premain to be dropped 19 * to .ctors segment, which is traversed by GCC crtbegin.o upon 20 * program startup. Except on a.out OpenBSD where it results in 21 * _GLOBAL_$I$premain() {premain();} being auto-generated by 22 * compiler... But one way or another this is believed to cover 23 * *all* GCC targets. */ 24#elif defined(_MSC_VER) 25# ifdef _WINDLL 26 __declspec(dllexport) /* this is essentially cosmetics... */ 27# endif 28 void FINGERPRINT_premain(void); 29 static int premain_wrapper(void) { FINGERPRINT_premain(); return 0; } 30# ifdef _WIN64 31# pragma section(".CRT$XCU",read) 32 __declspec(allocate(".CRT$XCU")) 33# else 34# pragma data_seg(".CRT$XCU") 35# endif 36 static int (*p)(void) = premain_wrapper; 37 /* This results in pointer to premain to appear in .CRT segment, 38 * which is traversed by Visual C run-time initialization code. 39 * This applies to both Win32 and [all flavors of] Win64. */ 40# pragma data_seg() 41#elif defined(__SUNPRO_C) 42 void FINGERPRINT_premain(void); 43# pragma init(FINGERPRINT_premain) 44 /* This results in a call to premain to appear in .init segment. */ 45#elif defined(__DECC) && (defined(__VMS) || defined(VMS)) 46 void FINGERPRINT_premain(void); 47# pragma __nostandard 48 globaldef { "LIB$INITIALIZ" } readonly _align (LONGWORD) 49 int spare[8] = {0}; 50 globaldef { "LIB$INITIALIZE" } readonly _align (LONGWORD) 51 void (*x_FINGERPRINT_premain)(void) = FINGERPRINT_premain; 52 /* Refer to LIB$INITIALIZE to ensure it exists in the image. */ 53 int lib$initialize(); 54 globaldef int (*lib_init_ref)() = lib$initialize; 55# pragma __standard 56#elif 0 57 The rest has to be taken care of through command line: 58 59 -Wl,-init,FINGERPRINT_premain on OSF1 and IRIX 60 -Wl,+init,FINGERPRINT_premain on HP-UX 61 -Wl,-binitfini:FINGERPRINT_premain on AIX 62 63 On ELF platforms this results in a call to premain to appear in 64 .init segment... 65#endif 66 67#ifndef HMAC_SHA1_SIG 68#define HMAC_SHA1_SIG "?have to make sure this string is unique" 69#endif 70 71static const unsigned char FINGERPRINT_ascii_value[40] = HMAC_SHA1_SIG; 72 73#define atox(c) ((c)>='a'?((c)-'a'+10):((c)>='A'?(c)-'A'+10:(c)-'0')) 74 75extern const void *FIPS_text_start(), *FIPS_text_end(); 76extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; 77extern unsigned char FIPS_signature[20]; 78extern unsigned int FIPS_incore_fingerprint(unsigned char *,unsigned int); 79 80/* 81 * As name suggests this code is executed prior main(). We use this 82 * opportunity to fingerprint sequestered code in virtual address 83 * space of target application. 84 */ 85void FINGERPRINT_premain(void) 86{ unsigned char sig[sizeof(FIPS_signature)]; 87 const unsigned char * volatile p=FINGERPRINT_ascii_value; 88 unsigned int len=sizeof(sig),i; 89 90 /* "volatilization" is done to disengage unwanted optimization... */ 91 if (*((volatile unsigned char *)p)=='?') 92 { if (FIPS_text_start()==NULL) 93 { fprintf(stderr,"FIPS_text_start() returns NULL\n"); 94 _exit(1); 95 } 96#if defined(DEBUG_FINGERPRINT_PREMAIN) 97 fprintf(stderr,".text:%p+%d=%p\n",FIPS_text_start(), 98 (int)((size_t)FIPS_text_end()-(size_t)FIPS_text_start()), 99 FIPS_text_end()); 100 fprintf(stderr,".rodata:%p+%d=%p\n",FIPS_rodata_start, 101 (int)((size_t)FIPS_rodata_end-(size_t)FIPS_rodata_start), 102 FIPS_rodata_end); 103#endif 104 105 len=FIPS_incore_fingerprint(sig,sizeof(sig)); 106 107 if (len!=sizeof(sig)) 108 { fprintf(stderr,"fingerprint length mismatch: %u\n",len); 109 _exit(1); 110 } 111 112 for (i=0;i<len;i++) printf("%02x",sig[i]); 113 printf("\n"); 114 fflush(stdout); 115 _exit(0); 116 } 117 else if (FIPS_signature[0]=='\0') do 118 { for (i=0;i<sizeof(FIPS_signature);i++,p+=2) 119 FIPS_signature[i] = (atox(p[0])<<4)|atox(p[1]); 120 121#if defined(DEBUG_FINGERPRINT_PREMAIN) 122 if (getenv("OPENSSL_FIPS")==NULL) break; 123 124 len=FIPS_incore_fingerprint(sig,sizeof(sig)); 125 126 if (memcmp(FIPS_signature,sig,sizeof(FIPS_signature))) 127 { fprintf(stderr,"FINGERPRINT_premain: FIPS_signature mismatch\n"); 128 _exit(1); 129 } 130#endif 131 } while(0); 132} 133 134#else 135 136#include <openssl/bio.h> 137#include <openssl/dso.h> 138#include <openssl/err.h> 139 140int main(int argc,char *argv[]) 141{ DSO *dso; 142 DSO_FUNC_TYPE func; 143 BIO *bio_err; 144 145 if (argc < 2) 146 { fprintf (stderr,"usage: %s libcrypto.dso\n",argv[0]); 147 return 1; 148 } 149 150 if ((bio_err=BIO_new(BIO_s_file())) == NULL) 151 { fprintf (stderr,"unable to allocate BIO\n"); 152 return 1; 153 } 154 BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); 155 ERR_load_crypto_strings(); 156 157 dso = DSO_load(NULL,argv[1],NULL,DSO_FLAG_NO_NAME_TRANSLATION); 158 if (dso == NULL) 159 { ERR_print_errors(bio_err); 160 return 1; 161 } 162 163 /* This is not normally reached, because FINGERPRINT_premain should 164 * have executed and terminated application already upon DSO_load... */ 165 func = DSO_bind_func(dso,"FINGERPRINT_premain"); 166 if (func == NULL) 167 { ERR_print_errors(bio_err); 168 return 1; 169 } 170 171 (*func)(); 172 173 return 0; 174} 175 176#endif 177