1 /*
2  * Copyright 2004-2025 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 <string.h>
11 
12 #include "apps.h"
13 #include "progs.h"
14 #include <openssl/bn.h>
15 
16 /* Consistent with RSA modulus size limit and the size of plausible individual primes */
17 #define BUFSIZE 4098
18 
19 typedef enum OPTION_choice {
20     OPT_COMMON,
21     OPT_HEX, OPT_GENERATE, OPT_BITS, OPT_SAFE, OPT_CHECKS,
22     OPT_PROV_ENUM,
23     OPT_IN_FILE
24 } OPTION_CHOICE;
25 
check_num(const char * s,const int is_hex)26 static int check_num(const char *s, const int is_hex)
27 {
28     int i;
29     /*
30      * It would make sense to use ossl_isxdigit and ossl_isdigit here,
31      * but ossl_ctype_check is a local symbol in libcrypto.so.
32      */
33     if (is_hex) {
34         for (i = 0; ('0' <= s[i] && s[i] <= '9')
35                     || ('A' <= s[i] && s[i] <= 'F')
36                     || ('a' <= s[i] && s[i] <= 'f'); i++);
37     } else {
38         for (i = 0;  '0' <= s[i] && s[i] <= '9'; i++);
39     }
40     return s[i] == 0;
41 }
42 
process_num(const char * s,const int is_hex)43 static void process_num(const char *s, const int is_hex)
44 {
45     int r;
46     BIGNUM *bn = NULL;
47 
48     r = check_num(s, is_hex);
49 
50     if (r)
51         r = is_hex ? BN_hex2bn(&bn, s) : BN_dec2bn(&bn, s);
52 
53     if (!r) {
54         BIO_printf(bio_err, "Failed to process value (%s)\n", s);
55         BN_free(bn);
56         return;
57     }
58 
59     BN_print(bio_out, bn);
60     r = BN_check_prime(bn, NULL, NULL);
61     BN_free(bn);
62     if (r < 0) {
63         BIO_printf(bio_err, "Error checking prime\n");
64         return;
65     }
66 
67     BIO_printf(bio_out, " (%s) %s prime\n", s, r == 1 ? "is" : "is not");
68 }
69 
70 const OPTIONS prime_options[] = {
71     {OPT_HELP_STR, 1, '-', "Usage: %s [options] [number...]\n"},
72 
73     OPT_SECTION("General"),
74     {"help", OPT_HELP, '-', "Display this summary"},
75     {"bits", OPT_BITS, 'p', "Size of number in bits"},
76     {"checks", OPT_CHECKS, 'p', "Number of checks"},
77     {"hex", OPT_HEX, '-',
78      "Enables hex format for output from prime generation or input to primality checking"},
79     {"in", OPT_IN_FILE, '-', "Provide file names containing numbers for primality checking"},
80 
81     OPT_SECTION("Output"),
82     {"generate", OPT_GENERATE, '-', "Generate a prime"},
83     {"safe", OPT_SAFE, '-',
84      "When used with -generate, generate a safe prime"},
85 
86     OPT_PROV_OPTIONS,
87 
88     OPT_PARAMETERS(),
89     {"number", 0, 0, "Number(s) to check for primality if not generating"},
90     {NULL}
91 };
92 
prime_main(int argc,char ** argv)93 int prime_main(int argc, char **argv)
94 {
95     BIGNUM *bn = NULL;
96     int hex = 0, generate = 0, bits = 0, safe = 0, ret = 1, in_file = 0;
97     char *prog;
98     OPTION_CHOICE o;
99     char file_read_buf[BUFSIZE] = { 0 };
100     BIO *in = NULL;
101 
102     prog = opt_init(argc, argv, prime_options);
103     while ((o = opt_next()) != OPT_EOF) {
104         switch (o) {
105         case OPT_EOF:
106         case OPT_ERR:
107 opthelp:
108             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
109             goto end;
110         case OPT_HELP:
111             opt_help(prime_options);
112             ret = 0;
113             goto end;
114         case OPT_HEX:
115             hex = 1;
116             break;
117         case OPT_GENERATE:
118             generate = 1;
119             break;
120         case OPT_BITS:
121             bits = atoi(opt_arg());
122             break;
123         case OPT_SAFE:
124             safe = 1;
125             break;
126         case OPT_CHECKS:
127             /* ignore parameter and argument */
128             opt_arg();
129             break;
130         case OPT_PROV_CASES:
131             if (!opt_provider(o))
132                 goto end;
133             break;
134         case OPT_IN_FILE:
135             in_file = 1;
136             break;
137         }
138     }
139 
140     /* Optional arguments are numbers to check. */
141     if (generate && !opt_check_rest_arg(NULL))
142         goto opthelp;
143     argc = opt_num_rest();
144     argv = opt_rest();
145     if (!generate && argc == 0) {
146         BIO_printf(bio_err, "Missing number (s) to check\n");
147         goto opthelp;
148     }
149 
150     if (generate) {
151         char *s;
152 
153         if (!bits) {
154             BIO_printf(bio_err, "Specify the number of bits.\n");
155             goto end;
156         }
157         bn = BN_new();
158         if (bn == NULL) {
159             BIO_printf(bio_err, "Out of memory.\n");
160             goto end;
161         }
162         if (!BN_generate_prime_ex(bn, bits, safe, NULL, NULL, NULL)) {
163             BIO_printf(bio_err, "Failed to generate prime.\n");
164             goto end;
165         }
166         s = hex ? BN_bn2hex(bn) : BN_bn2dec(bn);
167         if (s == NULL) {
168             BIO_printf(bio_err, "Out of memory.\n");
169             goto end;
170         }
171         BIO_printf(bio_out, "%s\n", s);
172         OPENSSL_free(s);
173     } else {
174         for ( ; *argv; argv++) {
175             int bytes_read = 0;
176 
177             if (!in_file) {
178                 process_num(argv[0], hex);
179             } else {
180                 in = bio_open_default_quiet(argv[0], 'r', 0);
181                 if (in == NULL) {
182                     BIO_printf(bio_err, "Error opening file %s\n", argv[0]);
183                     continue;
184                 }
185 
186                 while ((bytes_read = BIO_get_line(in, file_read_buf, BUFSIZE)) > 0) {
187                     size_t valid_digits_length;
188 
189                     /* Number is too long. Discard remainder of the line */
190                     if (bytes_read == BUFSIZE - 1 && file_read_buf[BUFSIZE - 2] != '\n') {
191                         BIO_printf(bio_err, "Value in %s is over the maximum size (%d digits)\n",
192                                    argv[0], BUFSIZE - 2);
193                         while (BIO_get_line(in, file_read_buf, BUFSIZE) == BUFSIZE - 1);
194                         continue;
195                     }
196 
197                     valid_digits_length = strspn(file_read_buf, "1234567890abcdefABCDEF");
198                     file_read_buf[valid_digits_length] = '\0';
199 
200                     process_num(file_read_buf, hex);
201                 }
202 
203                 if (bytes_read < 0)
204                     BIO_printf(bio_err, "Read error in %s\n", argv[0]);
205 
206                 BIO_free(in);
207             }
208         }
209     }
210 
211     ret = 0;
212  end:
213     BN_free(bn);
214     return ret;
215 }
216