1193645Ssimon/* ====================================================================
2193645Ssimon * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
3193645Ssimon * and usage in source and binary forms are granted according to the
4193645Ssimon * OpenSSL license.
5193645Ssimon */
6193645Ssimon
7193645Ssimon#include <stdio.h>
8193645Ssimon#include <stdlib.h>
9193645Ssimon#include <string.h>
10193645Ssimon#if defined(__unix) || defined(__unix__)
11296465Sdelphij# include <unistd.h>
12193645Ssimon#endif
13193645Ssimon
14193645Ssimon#ifndef FINGERPRINT_PREMAIN_DSO_LOAD
15193645Ssimon
16296465Sdelphij# if defined(__GNUC__) && __GNUC__>=2
17296465Sdelphijvoid FINGERPRINT_premain(void) __attribute__ ((constructor));
18296465Sdelphij  /*
19296465Sdelphij   * Most commonly this results in pointer to premain to be dropped to .ctors
20296465Sdelphij   * segment, which is traversed by GCC crtbegin.o upon program startup.
21296465Sdelphij   * Except on a.out OpenBSD where it results in _GLOBAL_$I$premain()
22296465Sdelphij   * {premain();} being auto-generated by compiler... But one way or another
23296465Sdelphij   * this is believed to cover *all* GCC targets.
24296465Sdelphij   */
25296465Sdelphij# elif defined(_MSC_VER)
26296465Sdelphij#  ifdef _WINDLL
27296465Sdelphij__declspec(dllexport)           /* this is essentially cosmetics... */
28296465Sdelphij#  endif
29296465Sdelphijvoid FINGERPRINT_premain(void);
30296465Sdelphijstatic int premain_wrapper(void)
31296465Sdelphij{
32296465Sdelphij    FINGERPRINT_premain();
33296465Sdelphij    return 0;
34296465Sdelphij}
35296465Sdelphij
36296465Sdelphij#  ifdef _WIN64
37296465Sdelphij#   pragma section(".CRT$XCU",read)
38296465Sdelphij__declspec(allocate(".CRT$XCU"))
39296465Sdelphij#  else
40296465Sdelphij#   pragma data_seg(".CRT$XCU")
41296465Sdelphij#  endif
42296465Sdelphijstatic int (*p) (void) = premain_wrapper;
43296465Sdelphij  /*
44296465Sdelphij   * This results in pointer to premain to appear in .CRT segment, which is
45296465Sdelphij   * traversed by Visual C run-time initialization code. This applies to both
46296465Sdelphij   * Win32 and [all flavors of] Win64.
47296465Sdelphij   */
48296465Sdelphij#  pragma data_seg()
49296465Sdelphij# elif defined(__SUNPRO_C)
50296465Sdelphijvoid FINGERPRINT_premain(void);
51296465Sdelphij#  pragma init(FINGERPRINT_premain)
52193645Ssimon  /* This results in a call to premain to appear in .init segment. */
53296465Sdelphij# elif defined(__DECC) && (defined(__VMS) || defined(VMS))
54296465Sdelphijvoid FINGERPRINT_premain(void);
55296465Sdelphij#  pragma __nostandard
56296465Sdelphijglobaldef {
57296465Sdelphij"LIB$INITIALIZ"} readonly _align(LONGWORD)
58296465Sdelphijint spare[8] = { 0 };
59193645Ssimon
60296465Sdelphijglobaldef {
61296465Sdelphij"LIB$INITIALIZE"} readonly _align(LONGWORD)
62193645Ssimon
63296465Sdelphijvoid (*x_FINGERPRINT_premain) (void) = FINGERPRINT_premain;
64296465Sdelphij  /* Refer to LIB$INITIALIZE to ensure it exists in the image. */
65296465Sdelphijint lib$initialize();
66296465Sdelphijglobaldef int (*lib_init_ref) () = lib$initialize;
67296465Sdelphij#  pragma __standard
68296465Sdelphij# elif 0
69296465SdelphijThe rest has to be taken care of through command line:-Wl, -init,
70296465Sdelphij    FINGERPRINT_premain on OSF1 and IRIX - Wl, +init,
71296465Sdelphij    FINGERPRINT_premain on HP - UX - Wl,
72296465Sdelphij    -binitfini:FINGERPRINT_premain on AIX On ELF platforms this results in a
73296465Sdelphij    call to premain to appear in.init segment ...
74296465Sdelphij# endif
75296465Sdelphij# ifndef HMAC_SHA1_SIG
76296465Sdelphij#  define HMAC_SHA1_SIG "?have to make sure this string is unique"
77296465Sdelphij# endif
78193645Ssimonstatic const unsigned char FINGERPRINT_ascii_value[40] = HMAC_SHA1_SIG;
79193645Ssimon
80296465Sdelphij# define atox(c) ((c)>='a'?((c)-'a'+10):((c)>='A'?(c)-'A'+10:(c)-'0'))
81193645Ssimon
82296465Sdelphijextern const void *FIPS_text_start(), *FIPS_text_end();
83193645Ssimonextern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
84296465Sdelphijextern unsigned char FIPS_signature[20];
85296465Sdelphijextern unsigned int FIPS_incore_fingerprint(unsigned char *, unsigned int);
86193645Ssimon
87193645Ssimon/*
88193645Ssimon * As name suggests this code is executed prior main(). We use this
89193645Ssimon * opportunity to fingerprint sequestered code in virtual address
90193645Ssimon * space of target application.
91193645Ssimon */
92193645Ssimonvoid FINGERPRINT_premain(void)
93296465Sdelphij{
94296465Sdelphij    unsigned char sig[sizeof(FIPS_signature)];
95296465Sdelphij    const unsigned char *volatile p = FINGERPRINT_ascii_value;
96296465Sdelphij    unsigned int len = sizeof(sig), i;
97193645Ssimon
98193645Ssimon    /* "volatilization" is done to disengage unwanted optimization... */
99296465Sdelphij    if (*((volatile unsigned char *)p) == '?') {
100296465Sdelphij        if (FIPS_text_start() == NULL) {
101296465Sdelphij            fprintf(stderr, "FIPS_text_start() returns NULL\n");
102296465Sdelphij            _exit(1);
103296465Sdelphij        }
104296465Sdelphij# if defined(DEBUG_FINGERPRINT_PREMAIN)
105296465Sdelphij        fprintf(stderr, ".text:%p+%d=%p\n", FIPS_text_start(),
106296465Sdelphij                (int)((size_t)FIPS_text_end() - (size_t)FIPS_text_start()),
107296465Sdelphij                FIPS_text_end());
108296465Sdelphij        fprintf(stderr, ".rodata:%p+%d=%p\n", FIPS_rodata_start,
109296465Sdelphij                (int)((size_t)FIPS_rodata_end - (size_t)FIPS_rodata_start),
110296465Sdelphij                FIPS_rodata_end);
111296465Sdelphij# endif
112193645Ssimon
113296465Sdelphij        len = FIPS_incore_fingerprint(sig, sizeof(sig));
114193645Ssimon
115296465Sdelphij        if (len != sizeof(sig)) {
116296465Sdelphij            fprintf(stderr, "fingerprint length mismatch: %u\n", len);
117296465Sdelphij            _exit(1);
118296465Sdelphij        }
119193645Ssimon
120296465Sdelphij        for (i = 0; i < len; i++)
121296465Sdelphij            printf("%02x", sig[i]);
122296465Sdelphij        printf("\n");
123296465Sdelphij        fflush(stdout);
124296465Sdelphij        _exit(0);
125296465Sdelphij    } else if (FIPS_signature[0] == '\0')
126296465Sdelphij        do {
127296465Sdelphij            for (i = 0; i < sizeof(FIPS_signature); i++, p += 2)
128296465Sdelphij                FIPS_signature[i] = (atox(p[0]) << 4) | atox(p[1]);
129193645Ssimon
130296465Sdelphij# if defined(DEBUG_FINGERPRINT_PREMAIN)
131296465Sdelphij            if (getenv("OPENSSL_FIPS") == NULL)
132296465Sdelphij                break;
133193645Ssimon
134296465Sdelphij            len = FIPS_incore_fingerprint(sig, sizeof(sig));
135193645Ssimon
136296465Sdelphij            if (memcmp(FIPS_signature, sig, sizeof(FIPS_signature))) {
137296465Sdelphij                fprintf(stderr,
138296465Sdelphij                        "FINGERPRINT_premain: FIPS_signature mismatch\n");
139296465Sdelphij                _exit(1);
140296465Sdelphij            }
141296465Sdelphij# endif
142296465Sdelphij        } while (0);
143193645Ssimon}
144193645Ssimon
145193645Ssimon#else
146193645Ssimon
147296465Sdelphij# include <openssl/bio.h>
148296465Sdelphij# include <openssl/dso.h>
149296465Sdelphij# include <openssl/err.h>
150193645Ssimon
151296465Sdelphijint main(int argc, char *argv[])
152296465Sdelphij{
153296465Sdelphij    DSO *dso;
154296465Sdelphij    DSO_FUNC_TYPE func;
155296465Sdelphij    BIO *bio_err;
156193645Ssimon
157296465Sdelphij    if (argc < 2) {
158296465Sdelphij        fprintf(stderr, "usage: %s libcrypto.dso\n", argv[0]);
159296465Sdelphij        return 1;
160193645Ssimon    }
161193645Ssimon
162296465Sdelphij    if ((bio_err = BIO_new(BIO_s_file())) == NULL) {
163296465Sdelphij        fprintf(stderr, "unable to allocate BIO\n");
164296465Sdelphij        return 1;
165193645Ssimon    }
166296465Sdelphij    BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
167193645Ssimon    ERR_load_crypto_strings();
168193645Ssimon
169296465Sdelphij    dso = DSO_load(NULL, argv[1], NULL, DSO_FLAG_NO_NAME_TRANSLATION);
170296465Sdelphij    if (dso == NULL) {
171296465Sdelphij        ERR_print_errors(bio_err);
172296465Sdelphij        return 1;
173193645Ssimon    }
174193645Ssimon
175296465Sdelphij    /*
176296465Sdelphij     * This is not normally reached, because FINGERPRINT_premain should have
177296465Sdelphij     * executed and terminated application already upon DSO_load...
178296465Sdelphij     */
179296465Sdelphij    func = DSO_bind_func(dso, "FINGERPRINT_premain");
180296465Sdelphij    if (func == NULL) {
181296465Sdelphij        ERR_print_errors(bio_err);
182296465Sdelphij        return 1;
183193645Ssimon    }
184193645Ssimon
185296465Sdelphij    (*func) ();
186193645Ssimon
187296465Sdelphij    return 0;
188193645Ssimon}
189193645Ssimon
190193645Ssimon#endif
191