/* ==================================================================== * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution * and usage in source and binary forms are granted according to the * OpenSSL license. */ #include #include #include #if defined(__unix) || defined(__unix__) # include #endif #ifndef FINGERPRINT_PREMAIN_DSO_LOAD # if defined(__GNUC__) && __GNUC__>=2 void FINGERPRINT_premain(void) __attribute__ ((constructor)); /* * Most commonly this results in pointer to premain to be dropped to .ctors * segment, which is traversed by GCC crtbegin.o upon program startup. * Except on a.out OpenBSD where it results in _GLOBAL_$I$premain() * {premain();} being auto-generated by compiler... But one way or another * this is believed to cover *all* GCC targets. */ # elif defined(_MSC_VER) # ifdef _WINDLL __declspec(dllexport) /* this is essentially cosmetics... */ # endif void FINGERPRINT_premain(void); static int premain_wrapper(void) { FINGERPRINT_premain(); return 0; } # ifdef _WIN64 # pragma section(".CRT$XCU",read) __declspec(allocate(".CRT$XCU")) # else # pragma data_seg(".CRT$XCU") # endif static int (*p) (void) = premain_wrapper; /* * This results in pointer to premain to appear in .CRT segment, which is * traversed by Visual C run-time initialization code. This applies to both * Win32 and [all flavors of] Win64. */ # pragma data_seg() # elif defined(__SUNPRO_C) void FINGERPRINT_premain(void); # pragma init(FINGERPRINT_premain) /* This results in a call to premain to appear in .init segment. */ # elif defined(__DECC) && (defined(__VMS) || defined(VMS)) void FINGERPRINT_premain(void); # pragma __nostandard globaldef { "LIB$INITIALIZ"} readonly _align(LONGWORD) int spare[8] = { 0 }; globaldef { "LIB$INITIALIZE"} readonly _align(LONGWORD) void (*x_FINGERPRINT_premain) (void) = FINGERPRINT_premain; /* Refer to LIB$INITIALIZE to ensure it exists in the image. */ int lib$initialize(); globaldef int (*lib_init_ref) () = lib$initialize; # pragma __standard # elif 0 The rest has to be taken care of through command line:-Wl, -init, FINGERPRINT_premain on OSF1 and IRIX - Wl, +init, FINGERPRINT_premain on HP - UX - Wl, -binitfini:FINGERPRINT_premain on AIX On ELF platforms this results in a call to premain to appear in.init segment ... # endif # ifndef HMAC_SHA1_SIG # define HMAC_SHA1_SIG "?have to make sure this string is unique" # endif static const unsigned char FINGERPRINT_ascii_value[40] = HMAC_SHA1_SIG; # define atox(c) ((c)>='a'?((c)-'a'+10):((c)>='A'?(c)-'A'+10:(c)-'0')) extern const void *FIPS_text_start(), *FIPS_text_end(); extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; extern unsigned char FIPS_signature[20]; extern unsigned int FIPS_incore_fingerprint(unsigned char *, unsigned int); /* * As name suggests this code is executed prior main(). We use this * opportunity to fingerprint sequestered code in virtual address * space of target application. */ void FINGERPRINT_premain(void) { unsigned char sig[sizeof(FIPS_signature)]; const unsigned char *volatile p = FINGERPRINT_ascii_value; unsigned int len = sizeof(sig), i; /* "volatilization" is done to disengage unwanted optimization... */ if (*((volatile unsigned char *)p) == '?') { if (FIPS_text_start() == NULL) { fprintf(stderr, "FIPS_text_start() returns NULL\n"); _exit(1); } # if defined(DEBUG_FINGERPRINT_PREMAIN) fprintf(stderr, ".text:%p+%d=%p\n", FIPS_text_start(), (int)((size_t)FIPS_text_end() - (size_t)FIPS_text_start()), FIPS_text_end()); fprintf(stderr, ".rodata:%p+%d=%p\n", FIPS_rodata_start, (int)((size_t)FIPS_rodata_end - (size_t)FIPS_rodata_start), FIPS_rodata_end); # endif len = FIPS_incore_fingerprint(sig, sizeof(sig)); if (len != sizeof(sig)) { fprintf(stderr, "fingerprint length mismatch: %u\n", len); _exit(1); } for (i = 0; i < len; i++) printf("%02x", sig[i]); printf("\n"); fflush(stdout); _exit(0); } else if (FIPS_signature[0] == '\0') do { for (i = 0; i < sizeof(FIPS_signature); i++, p += 2) FIPS_signature[i] = (atox(p[0]) << 4) | atox(p[1]); # if defined(DEBUG_FINGERPRINT_PREMAIN) if (getenv("OPENSSL_FIPS") == NULL) break; len = FIPS_incore_fingerprint(sig, sizeof(sig)); if (memcmp(FIPS_signature, sig, sizeof(FIPS_signature))) { fprintf(stderr, "FINGERPRINT_premain: FIPS_signature mismatch\n"); _exit(1); } # endif } while (0); } #else # include # include # include int main(int argc, char *argv[]) { DSO *dso; DSO_FUNC_TYPE func; BIO *bio_err; if (argc < 2) { fprintf(stderr, "usage: %s libcrypto.dso\n", argv[0]); return 1; } if ((bio_err = BIO_new(BIO_s_file())) == NULL) { fprintf(stderr, "unable to allocate BIO\n"); return 1; } BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); ERR_load_crypto_strings(); dso = DSO_load(NULL, argv[1], NULL, DSO_FLAG_NO_NAME_TRANSLATION); if (dso == NULL) { ERR_print_errors(bio_err); return 1; } /* * This is not normally reached, because FINGERPRINT_premain should have * executed and terminated application already upon DSO_load... */ func = DSO_bind_func(dso, "FINGERPRINT_premain"); if (func == NULL) { ERR_print_errors(bio_err); return 1; } (*func) (); return 0; } #endif