aboutsummaryrefslogtreecommitdiff
path: root/openssl/fips/fips_premain.c
blob: 165d2c5dc9741da4f7a67f8bc623c1f55e4f3c59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* ====================================================================
 * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
 * and usage in source and binary forms are granted according to the
 * OpenSSL license.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__unix) || defined(__unix__)
#include <unistd.h>
#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 <openssl/bio.h>
#include <openssl/dso.h>
#include <openssl/err.h>

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