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