155714Skris/* apps/dsaparam.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280297Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280297Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280297Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280297Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280297Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
59280297Sjkim#include <openssl/opensslconf.h> /* for OPENSSL_NO_DSA */
60280297Sjkim/*
61280297Sjkim * Until the key-gen callbacks are modified to use newer prototypes, we allow
62280297Sjkim * deprecated functions for openssl-internal code
63280297Sjkim */
64160814Ssimon#ifdef OPENSSL_NO_DEPRECATED
65280297Sjkim# undef OPENSSL_NO_DEPRECATED
66160814Ssimon#endif
67160814Ssimon
68109998Smarkm#ifndef OPENSSL_NO_DSA
69280297Sjkim# include <assert.h>
70280297Sjkim# include <stdio.h>
71280297Sjkim# include <stdlib.h>
72280297Sjkim# include <time.h>
73280297Sjkim# include <string.h>
74280297Sjkim# include "apps.h"
75280297Sjkim# include <openssl/bio.h>
76280297Sjkim# include <openssl/err.h>
77280297Sjkim# include <openssl/bn.h>
78280297Sjkim# include <openssl/dsa.h>
79280297Sjkim# include <openssl/x509.h>
80280297Sjkim# include <openssl/pem.h>
8155714Skris
82280297Sjkim# undef PROG
83280297Sjkim# define PROG    dsaparam_main
8455714Skris
85280297Sjkim/*-
86280297Sjkim * -inform arg  - input format - default PEM (DER or PEM)
8755714Skris * -outform arg - output format - default PEM
88280297Sjkim * -in arg      - input file - default stdin
89280297Sjkim * -out arg     - output file - default stdout
9055714Skris * -noout
9155714Skris * -text
9255714Skris * -C
9355714Skris * -noout
9455714Skris * -genkey
95160814Ssimon *  #ifdef GENCB_TEST
96160814Ssimon * -timebomb n  - interrupt keygen after <n> seconds
97160814Ssimon *  #endif
9855714Skris */
9955714Skris
100280297Sjkim# ifdef GENCB_TEST
10159191Skris
102160814Ssimonstatic int stop_keygen_flag = 0;
103160814Ssimon
104160814Ssimonstatic void timebomb_sigalarm(int foo)
105280297Sjkim{
106280297Sjkim    stop_keygen_flag = 1;
107280297Sjkim}
108160814Ssimon
109280297Sjkim# endif
110160814Ssimon
111160814Ssimonstatic int MS_CALLBACK dsa_cb(int p, int n, BN_GENCB *cb);
112160814Ssimon
11359191Skrisint MAIN(int, char **);
11459191Skris
11555714Skrisint MAIN(int argc, char **argv)
116280297Sjkim{
117280297Sjkim    DSA *dsa = NULL;
118280297Sjkim    int i, badops = 0, text = 0;
119280297Sjkim    BIO *in = NULL, *out = NULL;
120280297Sjkim    int informat, outformat, noout = 0, C = 0, ret = 1;
121280297Sjkim    char *infile, *outfile, *prog, *inrand = NULL;
122280297Sjkim    int numbits = -1, num, genkey = 0;
123280297Sjkim    int need_rand = 0;
124280297Sjkim    char *engine = NULL;
125312826Sjkim    ENGINE *e = NULL;
126280297Sjkim# ifdef GENCB_TEST
127280297Sjkim    int timebomb = 0;
128280297Sjkim# endif
12955714Skris
130280297Sjkim    apps_startup();
13155714Skris
132280297Sjkim    if (bio_err == NULL)
133280297Sjkim        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
134280297Sjkim            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
13555714Skris
136280297Sjkim    if (!load_config(bio_err, NULL))
137280297Sjkim        goto end;
138109998Smarkm
139280297Sjkim    infile = NULL;
140280297Sjkim    outfile = NULL;
141280297Sjkim    informat = FORMAT_PEM;
142280297Sjkim    outformat = FORMAT_PEM;
14355714Skris
144280297Sjkim    prog = argv[0];
145280297Sjkim    argc--;
146280297Sjkim    argv++;
147280297Sjkim    while (argc >= 1) {
148280297Sjkim        if (strcmp(*argv, "-inform") == 0) {
149280297Sjkim            if (--argc < 1)
150280297Sjkim                goto bad;
151280297Sjkim            informat = str2fmt(*(++argv));
152280297Sjkim        } else if (strcmp(*argv, "-outform") == 0) {
153280297Sjkim            if (--argc < 1)
154280297Sjkim                goto bad;
155280297Sjkim            outformat = str2fmt(*(++argv));
156280297Sjkim        } else if (strcmp(*argv, "-in") == 0) {
157280297Sjkim            if (--argc < 1)
158280297Sjkim                goto bad;
159280297Sjkim            infile = *(++argv);
160280297Sjkim        } else if (strcmp(*argv, "-out") == 0) {
161280297Sjkim            if (--argc < 1)
162280297Sjkim                goto bad;
163280297Sjkim            outfile = *(++argv);
164280297Sjkim        }
165280297Sjkim# ifndef OPENSSL_NO_ENGINE
166280297Sjkim        else if (strcmp(*argv, "-engine") == 0) {
167280297Sjkim            if (--argc < 1)
168280297Sjkim                goto bad;
169280297Sjkim            engine = *(++argv);
170280297Sjkim        }
171280297Sjkim# endif
172280297Sjkim# ifdef GENCB_TEST
173280297Sjkim        else if (strcmp(*argv, "-timebomb") == 0) {
174280297Sjkim            if (--argc < 1)
175280297Sjkim                goto bad;
176280297Sjkim            timebomb = atoi(*(++argv));
177280297Sjkim        }
178280297Sjkim# endif
179280297Sjkim        else if (strcmp(*argv, "-text") == 0)
180280297Sjkim            text = 1;
181280297Sjkim        else if (strcmp(*argv, "-C") == 0)
182280297Sjkim            C = 1;
183280297Sjkim        else if (strcmp(*argv, "-genkey") == 0) {
184280297Sjkim            genkey = 1;
185280297Sjkim            need_rand = 1;
186280297Sjkim        } else if (strcmp(*argv, "-rand") == 0) {
187280297Sjkim            if (--argc < 1)
188280297Sjkim                goto bad;
189280297Sjkim            inrand = *(++argv);
190280297Sjkim            need_rand = 1;
191280297Sjkim        } else if (strcmp(*argv, "-noout") == 0)
192280297Sjkim            noout = 1;
193280297Sjkim        else if (sscanf(*argv, "%d", &num) == 1) {
194280297Sjkim            /* generate a key */
195280297Sjkim            numbits = num;
196280297Sjkim            need_rand = 1;
197280297Sjkim        } else {
198280297Sjkim            BIO_printf(bio_err, "unknown option %s\n", *argv);
199280297Sjkim            badops = 1;
200280297Sjkim            break;
201280297Sjkim        }
202280297Sjkim        argc--;
203280297Sjkim        argv++;
204280297Sjkim    }
20555714Skris
206280297Sjkim    if (badops) {
207280297Sjkim bad:
208280297Sjkim        BIO_printf(bio_err, "%s [options] [bits] <infile >outfile\n", prog);
209280297Sjkim        BIO_printf(bio_err, "where options are\n");
210280297Sjkim        BIO_printf(bio_err, " -inform arg   input format - DER or PEM\n");
211280297Sjkim        BIO_printf(bio_err, " -outform arg  output format - DER or PEM\n");
212280297Sjkim        BIO_printf(bio_err, " -in arg       input file\n");
213280297Sjkim        BIO_printf(bio_err, " -out arg      output file\n");
214280297Sjkim        BIO_printf(bio_err, " -text         print as text\n");
215280297Sjkim        BIO_printf(bio_err, " -C            Output C code\n");
216280297Sjkim        BIO_printf(bio_err, " -noout        no output\n");
217280297Sjkim        BIO_printf(bio_err, " -genkey       generate a DSA key\n");
218280297Sjkim        BIO_printf(bio_err,
219280297Sjkim                   " -rand         files to use for random number input\n");
220280297Sjkim# ifndef OPENSSL_NO_ENGINE
221280297Sjkim        BIO_printf(bio_err,
222280297Sjkim                   " -engine e     use engine e, possibly a hardware device.\n");
223280297Sjkim# endif
224280297Sjkim# ifdef GENCB_TEST
225280297Sjkim        BIO_printf(bio_err,
226280297Sjkim                   " -timebomb n   interrupt keygen after <n> seconds\n");
227280297Sjkim# endif
228280297Sjkim        BIO_printf(bio_err,
229280297Sjkim                   " number        number of bits to use for generating private key\n");
230280297Sjkim        goto end;
231280297Sjkim    }
23255714Skris
233280297Sjkim    ERR_load_crypto_strings();
23455714Skris
235280297Sjkim    in = BIO_new(BIO_s_file());
236280297Sjkim    out = BIO_new(BIO_s_file());
237280297Sjkim    if ((in == NULL) || (out == NULL)) {
238280297Sjkim        ERR_print_errors(bio_err);
239280297Sjkim        goto end;
240280297Sjkim    }
24155714Skris
242280297Sjkim    if (infile == NULL)
243280297Sjkim        BIO_set_fp(in, stdin, BIO_NOCLOSE);
244280297Sjkim    else {
245280297Sjkim        if (BIO_read_filename(in, infile) <= 0) {
246280297Sjkim            perror(infile);
247280297Sjkim            goto end;
248280297Sjkim        }
249280297Sjkim    }
250280297Sjkim    if (outfile == NULL) {
251280297Sjkim        BIO_set_fp(out, stdout, BIO_NOCLOSE);
252280297Sjkim# ifdef OPENSSL_SYS_VMS
253280297Sjkim        {
254280297Sjkim            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
255280297Sjkim            out = BIO_push(tmpbio, out);
256280297Sjkim        }
257280297Sjkim# endif
258280297Sjkim    } else {
259280297Sjkim        if (BIO_write_filename(out, outfile) <= 0) {
260280297Sjkim            perror(outfile);
261280297Sjkim            goto end;
262280297Sjkim        }
263280297Sjkim    }
26455714Skris
265312826Sjkim    e = setup_engine(bio_err, engine, 0);
266109998Smarkm
267280297Sjkim    if (need_rand) {
268280297Sjkim        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
269280297Sjkim        if (inrand != NULL)
270280297Sjkim            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
271280297Sjkim                       app_RAND_load_files(inrand));
272280297Sjkim    }
27359191Skris
274280297Sjkim    if (numbits > 0) {
275280297Sjkim        BN_GENCB cb;
276280297Sjkim        BN_GENCB_set(&cb, dsa_cb, bio_err);
277280297Sjkim        assert(need_rand);
278280297Sjkim        dsa = DSA_new();
279280297Sjkim        if (!dsa) {
280280297Sjkim            BIO_printf(bio_err, "Error allocating DSA object\n");
281280297Sjkim            goto end;
282280297Sjkim        }
283280297Sjkim        BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n",
284280297Sjkim                   num);
285280297Sjkim        BIO_printf(bio_err, "This could take some time\n");
286280297Sjkim# ifdef GENCB_TEST
287280297Sjkim        if (timebomb > 0) {
288280297Sjkim            struct sigaction act;
289280297Sjkim            act.sa_handler = timebomb_sigalarm;
290280297Sjkim            act.sa_flags = 0;
291280297Sjkim            BIO_printf(bio_err,
292280297Sjkim                       "(though I'll stop it if not done within %d secs)\n",
293280297Sjkim                       timebomb);
294280297Sjkim            if (sigaction(SIGALRM, &act, NULL) != 0) {
295280297Sjkim                BIO_printf(bio_err, "Error, couldn't set SIGALRM handler\n");
296280297Sjkim                goto end;
297280297Sjkim            }
298280297Sjkim            alarm(timebomb);
299280297Sjkim        }
300280297Sjkim# endif
301280297Sjkim        if (!DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, &cb)) {
302280297Sjkim# ifdef GENCB_TEST
303280297Sjkim            if (stop_keygen_flag) {
304280297Sjkim                BIO_printf(bio_err, "DSA key generation time-stopped\n");
305280297Sjkim                /* This is an asked-for behaviour! */
306280297Sjkim                ret = 0;
307280297Sjkim                goto end;
308280297Sjkim            }
309280297Sjkim# endif
310280297Sjkim            ERR_print_errors(bio_err);
311280297Sjkim            BIO_printf(bio_err, "Error, DSA key generation failed\n");
312280297Sjkim            goto end;
313280297Sjkim        }
314280297Sjkim    } else if (informat == FORMAT_ASN1)
315280297Sjkim        dsa = d2i_DSAparams_bio(in, NULL);
316280297Sjkim    else if (informat == FORMAT_PEM)
317280297Sjkim        dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL);
318280297Sjkim    else {
319280297Sjkim        BIO_printf(bio_err, "bad input format specified\n");
320280297Sjkim        goto end;
321280297Sjkim    }
322280297Sjkim    if (dsa == NULL) {
323280297Sjkim        BIO_printf(bio_err, "unable to load DSA parameters\n");
324280297Sjkim        ERR_print_errors(bio_err);
325280297Sjkim        goto end;
326280297Sjkim    }
32755714Skris
328280297Sjkim    if (text) {
329280297Sjkim        DSAparams_print(out, dsa);
330280297Sjkim    }
33155714Skris
332280297Sjkim    if (C) {
333280297Sjkim        unsigned char *data;
334280297Sjkim        int l, len, bits_p;
33555714Skris
336280297Sjkim        len = BN_num_bytes(dsa->p);
337280297Sjkim        bits_p = BN_num_bits(dsa->p);
338280297Sjkim        data = (unsigned char *)OPENSSL_malloc(len + 20);
339280297Sjkim        if (data == NULL) {
340280297Sjkim            perror("OPENSSL_malloc");
341280297Sjkim            goto end;
342280297Sjkim        }
343280297Sjkim        l = BN_bn2bin(dsa->p, data);
344280297Sjkim        printf("static unsigned char dsa%d_p[]={", bits_p);
345280297Sjkim        for (i = 0; i < l; i++) {
346280297Sjkim            if ((i % 12) == 0)
347280297Sjkim                printf("\n\t");
348280297Sjkim            printf("0x%02X,", data[i]);
349280297Sjkim        }
350280297Sjkim        printf("\n\t};\n");
35155714Skris
352280297Sjkim        l = BN_bn2bin(dsa->q, data);
353280297Sjkim        printf("static unsigned char dsa%d_q[]={", bits_p);
354280297Sjkim        for (i = 0; i < l; i++) {
355280297Sjkim            if ((i % 12) == 0)
356280297Sjkim                printf("\n\t");
357280297Sjkim            printf("0x%02X,", data[i]);
358280297Sjkim        }
359280297Sjkim        printf("\n\t};\n");
36055714Skris
361280297Sjkim        l = BN_bn2bin(dsa->g, data);
362280297Sjkim        printf("static unsigned char dsa%d_g[]={", bits_p);
363280297Sjkim        for (i = 0; i < l; i++) {
364280297Sjkim            if ((i % 12) == 0)
365280297Sjkim                printf("\n\t");
366280297Sjkim            printf("0x%02X,", data[i]);
367280297Sjkim        }
368280297Sjkim        printf("\n\t};\n\n");
36955714Skris
370280297Sjkim        printf("DSA *get_dsa%d()\n\t{\n", bits_p);
371280297Sjkim        printf("\tDSA *dsa;\n\n");
372280297Sjkim        printf("\tif ((dsa=DSA_new()) == NULL) return(NULL);\n");
373280297Sjkim        printf("\tdsa->p=BN_bin2bn(dsa%d_p,sizeof(dsa%d_p),NULL);\n",
374280297Sjkim               bits_p, bits_p);
375280297Sjkim        printf("\tdsa->q=BN_bin2bn(dsa%d_q,sizeof(dsa%d_q),NULL);\n",
376280297Sjkim               bits_p, bits_p);
377280297Sjkim        printf("\tdsa->g=BN_bin2bn(dsa%d_g,sizeof(dsa%d_g),NULL);\n",
378280297Sjkim               bits_p, bits_p);
379280297Sjkim        printf
380280297Sjkim            ("\tif ((dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))\n");
381280297Sjkim        printf("\t\t{ DSA_free(dsa); return(NULL); }\n");
382280297Sjkim        printf("\treturn(dsa);\n\t}\n");
383280297Sjkim    }
38455714Skris
385331638Sjkim    if (outformat == FORMAT_ASN1 && genkey)
386331638Sjkim        noout = 1;
387331638Sjkim
388280297Sjkim    if (!noout) {
389280297Sjkim        if (outformat == FORMAT_ASN1)
390280297Sjkim            i = i2d_DSAparams_bio(out, dsa);
391280297Sjkim        else if (outformat == FORMAT_PEM)
392280297Sjkim            i = PEM_write_bio_DSAparams(out, dsa);
393280297Sjkim        else {
394280297Sjkim            BIO_printf(bio_err, "bad output format specified for outfile\n");
395280297Sjkim            goto end;
396280297Sjkim        }
397280297Sjkim        if (!i) {
398280297Sjkim            BIO_printf(bio_err, "unable to write DSA parameters\n");
399280297Sjkim            ERR_print_errors(bio_err);
400280297Sjkim            goto end;
401280297Sjkim        }
402280297Sjkim    }
403280297Sjkim    if (genkey) {
404280297Sjkim        DSA *dsakey;
40555714Skris
406280297Sjkim        assert(need_rand);
407280297Sjkim        if ((dsakey = DSAparams_dup(dsa)) == NULL)
408280297Sjkim            goto end;
409280297Sjkim        if (!DSA_generate_key(dsakey)) {
410280297Sjkim            ERR_print_errors(bio_err);
411280297Sjkim            DSA_free(dsakey);
412280297Sjkim            goto end;
413280297Sjkim        }
414280297Sjkim        if (outformat == FORMAT_ASN1)
415280297Sjkim            i = i2d_DSAPrivateKey_bio(out, dsakey);
416280297Sjkim        else if (outformat == FORMAT_PEM)
417280297Sjkim            i = PEM_write_bio_DSAPrivateKey(out, dsakey, NULL, NULL, 0, NULL,
418280297Sjkim                                            NULL);
419280297Sjkim        else {
420280297Sjkim            BIO_printf(bio_err, "bad output format specified for outfile\n");
421280297Sjkim            DSA_free(dsakey);
422280297Sjkim            goto end;
423280297Sjkim        }
424280297Sjkim        DSA_free(dsakey);
425280297Sjkim    }
426280297Sjkim    if (need_rand)
427280297Sjkim        app_RAND_write_file(NULL, bio_err);
428280297Sjkim    ret = 0;
429280297Sjkim end:
430280297Sjkim    if (in != NULL)
431280297Sjkim        BIO_free(in);
432280297Sjkim    if (out != NULL)
433280297Sjkim        BIO_free_all(out);
434280297Sjkim    if (dsa != NULL)
435280297Sjkim        DSA_free(dsa);
436312826Sjkim    release_engine(e);
437280297Sjkim    apps_shutdown();
438280297Sjkim    OPENSSL_EXIT(ret);
439280297Sjkim}
44055714Skris
441160814Ssimonstatic int MS_CALLBACK dsa_cb(int p, int n, BN_GENCB *cb)
442280297Sjkim{
443280297Sjkim    char c = '*';
44455714Skris
445280297Sjkim    if (p == 0)
446280297Sjkim        c = '.';
447280297Sjkim    if (p == 1)
448280297Sjkim        c = '+';
449280297Sjkim    if (p == 2)
450280297Sjkim        c = '*';
451280297Sjkim    if (p == 3)
452280297Sjkim        c = '\n';
453280297Sjkim    BIO_write(cb->arg, &c, 1);
454280297Sjkim    (void)BIO_flush(cb->arg);
455280297Sjkim# ifdef LINT
456280297Sjkim    p = n;
457280297Sjkim# endif
458280297Sjkim# ifdef GENCB_TEST
459280297Sjkim    if (stop_keygen_flag)
460280297Sjkim        return 0;
461280297Sjkim# endif
462280297Sjkim    return 1;
463280297Sjkim}
464280297Sjkim#else                           /* !OPENSSL_NO_DSA */
465205128Ssimon
466205128Ssimon# if PEDANTIC
467280297Sjkimstatic void *dummy = &dummy;
468205128Ssimon# endif
469205128Ssimon
47055714Skris#endif
471