1 /* 2 * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 13 #include <openssl/e_os2.h> 14 15 #ifdef OPENSSL_SYS_UNIX 16 #include <sys/stat.h> 17 #include <sys/resource.h> 18 #include <openssl/pem.h> 19 #include <openssl/x509.h> 20 #include <openssl/err.h> 21 #include <openssl/bio.h> 22 #include "internal/e_os.h" 23 #if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L 24 25 #ifndef timersub 26 /* struct timeval * subtraction; a must be greater than or equal to b */ 27 #define timersub(a, b, res) \ 28 do { \ 29 (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 30 if ((a)->tv_usec < (b)->tv_usec) { \ 31 (res)->tv_usec = (a)->tv_usec + 1000000 - (b)->tv_usec; \ 32 --(res)->tv_sec; \ 33 } else { \ 34 (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 35 } \ 36 } while (0) 37 #endif 38 39 static char *prog; 40 41 static void readx509(const char *contents, int size) 42 { 43 X509 *x = NULL; 44 BIO *b = BIO_new_mem_buf(contents, size); 45 46 if (b == NULL) { 47 ERR_print_errors_fp(stderr); 48 exit(EXIT_FAILURE); 49 } 50 PEM_read_bio_X509(b, &x, 0, NULL); 51 if (x == NULL) { 52 ERR_print_errors_fp(stderr); 53 exit(EXIT_FAILURE); 54 } 55 X509_free(x); 56 BIO_free(b); 57 } 58 59 static void readpkey(const char *contents, int size) 60 { 61 BIO *b = BIO_new_mem_buf(contents, size); 62 EVP_PKEY *pkey; 63 64 if (b == NULL) { 65 ERR_print_errors_fp(stderr); 66 exit(EXIT_FAILURE); 67 } 68 pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL); 69 if (pkey == NULL) { 70 ERR_print_errors_fp(stderr); 71 exit(EXIT_FAILURE); 72 } 73 74 EVP_PKEY_free(pkey); 75 BIO_free(b); 76 } 77 78 static void print_timeval(const char *what, struct timeval *tp) 79 { 80 printf("%s %d sec %d microsec\n", what, (int)tp->tv_sec, (int)tp->tv_usec); 81 } 82 83 static void usage(void) 84 { 85 fprintf(stderr, "Usage: %s [flags] pem-file\n", prog); 86 fprintf(stderr, "Flags, with the default being '-wc':\n"); 87 fprintf(stderr, " -c # Repeat count\n"); 88 fprintf(stderr, " -d Debugging output (minimal)\n"); 89 fprintf(stderr, " -w<T> What to load T is a single character:\n"); 90 fprintf(stderr, " c for cert\n"); 91 fprintf(stderr, " p for private key\n"); 92 exit(EXIT_FAILURE); 93 } 94 #endif 95 #endif 96 97 #if !defined(RUSAGE_SELF) && defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L 98 #include <sys/times.h> 99 #endif 100 101 int main(int ac, char **av) 102 { 103 #if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L 104 int i, debug = 0, count = 100, what = 'c'; 105 struct stat sb; 106 FILE *fp; 107 char *contents; 108 #if !defined(RUSAGE_SELF) 109 struct tms rus; 110 struct timeval u_start, u_end, u_elapsed; 111 struct timeval s_start, s_end, s_elapsed; 112 #else 113 struct rusage start, end, elapsed; 114 #endif 115 struct timeval e_start, e_end, e_elapsed; 116 117 /* Parse JCL. */ 118 prog = av[0]; 119 while ((i = getopt(ac, av, "c:dw:")) != EOF) { 120 switch (i) { 121 default: 122 usage(); 123 break; 124 case 'c': 125 if ((count = atoi(optarg)) < 0) 126 usage(); 127 break; 128 case 'd': 129 debug = 1; 130 break; 131 case 'w': 132 if (optarg[1] != '\0') 133 usage(); 134 switch (*optarg) { 135 default: 136 usage(); 137 break; 138 case 'c': 139 case 'p': 140 what = *optarg; 141 break; 142 } 143 break; 144 } 145 } 146 ac -= optind; 147 av += optind; 148 149 /* Read input file. */ 150 if (av[0] == NULL) 151 usage(); 152 if (stat(av[0], &sb) < 0) { 153 perror(av[0]); 154 exit(EXIT_FAILURE); 155 } 156 contents = OPENSSL_malloc(sb.st_size + 1); 157 if (contents == NULL) { 158 perror("malloc"); 159 exit(EXIT_FAILURE); 160 } 161 fp = fopen(av[0], "r"); 162 if ((long)fread(contents, 1, sb.st_size, fp) != sb.st_size) { 163 perror("fread"); 164 exit(EXIT_FAILURE); 165 } 166 contents[sb.st_size] = '\0'; 167 fclose(fp); 168 if (debug) 169 printf(">%s<\n", contents); 170 171 /* Try to prep system cache, etc. */ 172 for (i = 10; i > 0; i--) { 173 switch (what) { 174 case 'c': 175 readx509(contents, (int)sb.st_size); 176 break; 177 case 'p': 178 readpkey(contents, (int)sb.st_size); 179 break; 180 } 181 } 182 183 if (gettimeofday(&e_start, NULL) < 0) { 184 perror("elapsed start"); 185 exit(EXIT_FAILURE); 186 } 187 #if !defined(RUSAGE_SELF) 188 times(&rus); 189 u_start.tv_sec = rus.tms_utime / CLOCKS_PER_SEC; 190 u_start.tv_usec = (rus.tms_utime * 1000000) / CLOCKS_PER_SEC; 191 s_start.tv_sec = rus.tms_stime / CLOCKS_PER_SEC; 192 s_start.tv_usec = (rus.tms_stime * 1000000) / CLOCKS_PER_SEC; 193 #else 194 if (getrusage(RUSAGE_SELF, &start) < 0) { 195 perror("start"); 196 exit(EXIT_FAILURE); 197 } 198 #endif 199 for (i = count; i > 0; i--) { 200 switch (what) { 201 case 'c': 202 readx509(contents, (int)sb.st_size); 203 break; 204 case 'p': 205 readpkey(contents, (int)sb.st_size); 206 break; 207 } 208 } 209 #if !defined(RUSAGE_SELF) 210 times(&rus); 211 u_end.tv_sec = rus.tms_utime / CLOCKS_PER_SEC; 212 u_end.tv_usec = (rus.tms_utime * 1000000) / CLOCKS_PER_SEC; 213 s_end.tv_sec = rus.tms_stime / CLOCKS_PER_SEC; 214 s_end.tv_usec = (rus.tms_stime * 1000000) / CLOCKS_PER_SEC; 215 #else 216 if (getrusage(RUSAGE_SELF, &end) < 0) { 217 perror("getrusage"); 218 exit(EXIT_FAILURE); 219 } 220 #endif 221 if (gettimeofday(&e_end, NULL) < 0) { 222 perror("gettimeofday"); 223 exit(EXIT_FAILURE); 224 } 225 226 #if !defined(RUSAGE_SELF) 227 timersub(&u_end, &u_start, &u_elapsed); 228 timersub(&s_end, &s_start, &s_elapsed); 229 #else 230 timersub(&end.ru_utime, &start.ru_stime, &elapsed.ru_stime); 231 timersub(&end.ru_utime, &start.ru_utime, &elapsed.ru_utime); 232 #endif 233 timersub(&e_end, &e_start, &e_elapsed); 234 #if !defined(RUSAGE_SELF) 235 print_timeval("user ", &u_elapsed); 236 print_timeval("sys ", &s_elapsed); 237 #else 238 print_timeval("user ", &elapsed.ru_utime); 239 print_timeval("sys ", &elapsed.ru_stime); 240 #endif 241 if (debug) 242 print_timeval("elapsed??", &e_elapsed); 243 244 OPENSSL_free(contents); 245 return EXIT_SUCCESS; 246 #else 247 fprintf(stderr, 248 "This tool is not supported on this platform for lack of POSIX1.2001 support\n"); 249 exit(EXIT_FAILURE); 250 #endif 251 } 252