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