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