dsa_subr.C
上传用户:zbbssh
上传日期:2007-01-08
资源大小:196k
文件大小:17k
源码类别:

CA认证

开发平台:

C/C++

  1. /*
  2. ------------------------------------------------------------------
  3.   Copyright
  4.   Sun Microsystems, Inc.
  5.   Copyright (C) 1994, 1995, 1996 Sun Microsystems, Inc.  All Rights
  6.   Reserved.
  7.   Permission is hereby granted, free of charge, to any person
  8.   obtaining a copy of this software and associated documentation
  9.   files (the "Software"), to deal in the Software without
  10.   restriction, including without limitation the rights to use,
  11.   copy, modify, merge, publish, distribute, sublicense, and/or sell
  12.   copies of the Software or derivatives of the Software, and to 
  13.   permit persons to whom the Software or its derivatives is furnished 
  14.   to do so, subject to the following conditions:
  15.   The above copyright notice and this permission notice shall be
  16.   included in all copies or substantial portions of the Software.
  17.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18.   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19.   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20.   NONINFRINGEMENT.  IN NO EVENT SHALL SUN MICROSYSTEMS, INC., BE LIABLE
  21.   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22.   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23.   CONNECTION WITH THE SOFTWARE OR DERIVATES OF THIS SOFTWARE OR 
  24.   THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.   Except as contained in this notice, the name of Sun Microsystems, Inc.
  26.   shall not be used in advertising or otherwise to promote
  27.   the sale, use or other dealings in this Software or its derivatives 
  28.   without prior written authorization from Sun Microsystems, Inc.
  29. */
  30. #pragma ident "@(#)dsa_subr.C 1.8 96/01/30"
  31. /*
  32.  * Copyright (c) 1995, 1996  Colin Plumb.  All rights reserved.
  33.  * For licensing and other legal details, see the file legal.c.
  34.  *
  35.  * This generates DSA primes using a (hopefully) clearly
  36.  * defined algorithm, based on David Kravitz's "kosherizer".
  37.  * It is not, however, identical.
  38.  */
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include "Bstream.h"
  42. #include "Bigint.h"
  43. #include "Time.h"
  44. #include "asn1_der.h"
  45. #include "ObjId.h"
  46. #include "Name.h"
  47. #include "X509Cert.h"
  48. #include "Sig.h"
  49. #include "bn.h"
  50. #include "bn_glue.h"
  51. #include "prime.h"
  52. #include "sha.h"
  53. #include "dsa.h"
  54. #include "ca.h"
  55. #include "utils.h"
  56. /*
  57.  * Generate a random bignum of a specified length.
  58.  */
  59. int
  60. genRandBn(struct BigNum *bn, unsigned bits)
  61. {
  62. unsigned char buf[64];
  63. unsigned bytes = (bits+7)/8;
  64. unsigned l = 0; /* Current position */
  65. unsigned i;
  66. bnSetQ(bn, 0);
  67. if (!bits)
  68. return 0;
  69. /* Do low-order portions */
  70. while (bytes > sizeof(buf)) {
  71. randpool_getbytes(buf, sizeof(buf));
  72. if (bnInsertBigBytes(bn, buf, l, sizeof(buf)) < 0)
  73. return -1;
  74. l += sizeof(buf);
  75. }
  76. /* Do the most-significant chunk */
  77. randpool_getbytes(buf, bytes);
  78. /* Mask off excess high bits */
  79. buf[0] &= 255 >> (-bits & 7);
  80. return bnInsertBigBytes(bn, buf, l, bytes);
  81. }
  82. /*
  83.  * DSA signature.
  84.  * Inputs:
  85.  * p - a large prime
  86.  * q - a 160-bit prime factor of (p-1).  (Actually, any length will do.)
  87.  * g - a generator of order q modulo p, i.e. g^q == 1 (mod p)
  88.  * x - the secret key, 1 < x < q-1
  89.  * hash - the value to be signed
  90.  * k - the per-signature random number, 1 < k < q-1
  91.  * Outputs: r, s
  92.  *
  93.  * returns 0 on success and -1 on failure (out of memory or bogus key)
  94.  */
  95. static int
  96. dsaSign(struct BigNum const *p, struct BigNum const *q,
  97. struct BigNum const *g, struct BigNum const *x,
  98. struct BigNum const *hash, struct BigNum const *k,
  99. struct BigNum *r, struct BigNum *s)
  100. {
  101. int retval = -1;
  102. struct BigNum t;
  103. /* Sanity check all the values */
  104. if ((bnLSWord(p) & 1) == 0|| (bnLSWord(q) & 1) == 0 ||
  105.     bnCmp(p, q) <= 0 || bnCmp(p, g) <= 0 ||
  106.     bnCmp(q, x) <= 0 || bnCmp(q, k) <= 0 ||
  107.     bnBits(x) <= 1 || bnBits(k) <= 1)
  108. return -1;
  109. bnBegin(&t);
  110. printf("Error: Cannot Signn");
  111. retval = -1;
  112. failed:
  113. bnEnd(&t);
  114. return retval;
  115. }
  116. Bstream
  117. DSA_sign(const Bigint& p, const Bigint& q, const Bigint& g,
  118. const Bigint& x, const Bstream& data) 
  119. {
  120. struct BigNum prime, subprime, gen, secret, k, s_r, s_s, hash;
  121. Bstream nullbstr, localhash;
  122. int retval;
  123. bnInit(); // just in case ...
  124. // locally compute the hash
  125. localhash = messageDigest(data, dsaWithSHA);
  126. // initialize bignums and convert as neccessary
  127. bnBegin(&prime);
  128. bnBegin(&subprime);
  129. bnBegin(&gen);
  130. bnBegin(&secret);
  131. bnBegin(&hash);
  132. bnBegin(&k);
  133. bnBegin(&s_r);
  134. bnBegin(&s_s);
  135. Bigint_to_BigNum(&p, &prime);
  136. Bigint_to_BigNum(&q, &subprime);
  137. Bigint_to_BigNum(&g, &gen);
  138. Bigint_to_BigNum(&x, &secret);
  139. Bstream_to_BigNum(&localhash, &hash);
  140. // generate k uniformly between 0 and q-1
  141. camode = TRUE;
  142. if (genRandBn(&k, bnBits(&subprime)+8) < 0 ||
  143.     bnMod(&k, &k, &subprime) <0) {
  144. fprintf(stderr, "DSA_sign: failed to generate 'k'n");
  145. goto failed;
  146. }
  147. retval = dsaSign(&prime, &subprime, &gen, &secret, &hash, &k,
  148. &s_r, &s_s);
  149. if (retval == 0) {
  150. Bigint r, s;
  151. BigNum_to_Bigint(&s_r, &r);
  152. BigNum_to_Bigint(&s_s, &s);
  153. nullbstr = asn1_der_encode_dsa_signature(r, s);
  154. } else
  155. fprintf(stderr, "DSA_sign: failed to signn");
  156. failed:
  157. bnEnd(&prime);
  158. bnEnd(&subprime);
  159. bnEnd(&gen);
  160. bnEnd(&secret);
  161. bnEnd(&k);
  162. bnEnd(&hash);
  163. bnEnd(&s_r);
  164. bnEnd(&s_s);
  165. return (nullbstr);
  166. }
  167. /*
  168.  * DSA signature verification.
  169.  * Inputs:
  170.  * p - a large prime
  171.  * q - a 160-bit prime factor of (p-1).  (Actually, any length will do.)
  172.  * g - a generator of order q modulo p, i.e. g^q == 1 (mod p)
  173.  * y - the public key, g^x mod p, 1 < y < p-1
  174.  * r = the signature (first part)
  175.  * s = the signature (second part)
  176.  * hash - the value to be signed
  177.  * Outputs:
  178.  * Returns 1 for a good signature, 0 for bad, and -1 on error.
  179.  *
  180.  */
  181. static int
  182. dsaVerify(struct BigNum const *p, struct BigNum const *q,
  183.           struct BigNum const *g, struct BigNum const *y,
  184.           struct BigNum const *r, struct BigNum const *s,
  185.           struct BigNum const *hash)
  186. {
  187. struct BigNum v, u1, u2;
  188. int retval = -1;
  189. int i;
  190. /* Sanity check all the values */
  191. if ((bnLSWord(p) & 1) == 0|| (bnLSWord(q) & 1) == 0 ||
  192.     bnCmp(p, q) <= 0 || bnCmp(p, g) <= 0 ||
  193.     bnCmp(q, r) <= 0 || bnCmp(q, s) <= 0)
  194. return 0; // Messed up -> all signatures are bad
  195. bnBegin(&v);
  196. bnBegin(&u1);
  197. bnBegin(&u2);
  198. printf("Error: Cannot Verifyn");
  199. retval = -1; // An Error since we can't verify
  200. failed:
  201. bnEnd(&u2);
  202. bnEnd(&u1);
  203. bnEnd(&v);
  204. return retval;
  205. }
  206. VerifyResult
  207. DSA_verify(const Bstream& data, const Bstream& sig, const PubKey& pubkey,
  208. AlgId sigalg)
  209. {
  210. Bigint p, q, g, y, r, s;
  211. Bstream localhash;
  212. struct BigNum prime, subprime, gen, pub, s_r, s_s, hash;
  213. int retval;
  214. bnInit(); // just in case ....
  215. // decode the DSA parameters, and public key
  216. Bstream der_stream = pubkey.keytype.params;
  217. retval = asn1_der_decode_dsa_params(der_stream, p, q, g);
  218. if (retval < 0) {
  219. fprintf(stderr, "DSA_verify: Bad key params encodingn");
  220. return (INVALID_SIG);
  221. }
  222. der_stream = pubkey.key;
  223. y = Bigint(der_stream.getdatap(), der_stream.getlength());
  224. if (y == Bigint((short)0)) {
  225. fprintf(stderr, "DSA_verify: Bad publickey encodingn");
  226. return (INVALID_SIG);
  227. }
  228. // decode the signature into its components
  229. retval = asn1_der_decode_dsa_signature(sig, r, s);
  230. if (retval < 0) {
  231. fprintf(stderr, "DSA_verify: Bad signature encodingn");
  232. return (INVALID_SIG);
  233. }
  234. // Locally compute message digest over the input portion
  235. localhash = messageDigest(data, sigalg.algid);
  236. // intialize bignums and convert as necessary
  237. bnBegin(&prime);
  238. bnBegin(&subprime);
  239. bnBegin(&gen);
  240. bnBegin(&pub);
  241. bnBegin(&s_r);
  242. bnBegin(&s_s);
  243. bnBegin(&hash);
  244. Bigint_to_BigNum(&p, &prime);
  245. Bigint_to_BigNum(&q, &subprime);
  246. Bigint_to_BigNum(&g, &gen);
  247. Bigint_to_BigNum(&y, &pub);
  248. Bigint_to_BigNum(&r, &s_r);
  249. Bigint_to_BigNum(&s, &s_s);
  250. Bstream_to_BigNum(&localhash, &hash);
  251. retval = dsaVerify(&prime, &subprime, &gen, &pub, &s_r, &s_s, &hash);
  252. bnEnd(&prime);
  253. bnEnd(&subprime);
  254. bnEnd(&gen);
  255. bnEnd(&pub);
  256. bnEnd(&s_r);
  257. bnEnd(&s_s);
  258. bnEnd(&hash);
  259. if (retval <= 0) {
  260. fprintf(stderr, "DSA_verify: Bad signaturen");
  261. return (INVALID_SIG);
  262. }
  263. return (VALID);
  264. }
  265. // ASN.1 routines for DSA encoding/decoding
  266. int
  267. asn1_der_decode_dsa_privkey(Bstream der_stream, Bigint& p, Bigint& q,
  268. Bigint& g, Bigint& x)
  269. {
  270.         byte tmp = 0;
  271.         int seqlen, retval = 0;
  272.         ObjId oid;
  273.         Bigint version;
  274. Bstream DSAprivkey;
  275. SEQUENCE {
  276. INTEGER(version); // version of syntax
  277. SEQUENCE { // privkey alg id
  278. OBJECT_IDENTIFIER(oid);
  279.                  SEQUENCE {
  280.                          INTEGER(p);
  281.                          INTEGER(q);
  282.                          INTEGER(g);
  283.                  }
  284.          }
  285. OCTET_STRING(DSAprivkey);
  286. // XXX -- leaving out the optional attributes stuff
  287. }
  288. retval = asn1_der_decode_integer(DSAprivkey, x);
  289.         return (retval);
  290. }
  291. Bstream
  292. asn1_der_encode_dsa_privkey(Bigint& prime, Bigint& subprime,
  293. Bigint& generator, Bigint& secret)
  294. {
  295. Bstream tmpstr, params;
  296. ObjId keyoid = dsa;
  297. // version=0
  298. tmpstr = asn1_der_encode_integer((short)0);
  299. // params
  300. params = asn1_der_encode_sequence(
  301. asn1_der_encode_integer(prime) +
  302. asn1_der_encode_integer(subprime) +
  303. asn1_der_encode_integer(generator));
  304. // subject private key alg id
  305. params = keyoid.encode() + params;
  306. params = asn1_der_encode_sequence(params);
  307. // subject private key
  308. tmpstr = tmpstr + params +
  309. asn1_der_encode_octet_string(
  310. asn1_der_encode_integer(secret));
  311. // XXX -- no attribute encoding for now
  312. tmpstr = asn1_der_encode_sequence(tmpstr);
  313. return (tmpstr);
  314. }
  315. int
  316. asn1_der_decode_dsa_signature(Bstream der_stream, Bigint& r, Bigint& s)
  317. {
  318. byte tmp = 0;
  319. int seqlen, retval;
  320.  
  321. // wrapper BIT_STRING decoding is done in-line
  322. SEQUENCE {
  323. INTEGER(r);
  324. INTEGER(s);
  325. }
  326. return (0);
  327. }
  328. Bstream
  329. asn1_der_encode_dsa_signature(Bigint& r, Bigint& s)
  330. {
  331. Bstream tmpstr;
  332. tmpstr = asn1_der_encode_sequence(
  333. asn1_der_encode_integer(r) +
  334. asn1_der_encode_integer(s));
  335. // final bit string encoding is done in-line
  336. return (tmpstr);
  337. }
  338. int
  339. asn1_der_decode_dsa_params(Bstream der_stream, Bigint& p, Bigint& q, Bigint& g)
  340. {
  341.         byte tmp = 0;
  342.         int seqlen, retval;
  343.         ObjId oid;
  344.  
  345. SEQUENCE {
  346. INTEGER(p);
  347. INTEGER(q);
  348. INTEGER(g);
  349. }
  350. return (0);
  351. }
  352. int
  353. asn1_der_decode_dsa_publickey(Bstream der_stream, Bigint& p, Bigint& q,
  354. Bigint& g, Bigint& y)
  355. {
  356.         byte tmp = 0;
  357.         int seqlen, retval = 0;
  358.         ObjId oid;
  359. Bstream pub;
  360.  
  361.         SEQUENCE { // subject public key info
  362. SEQUENCE { // subject public key alg id
  363.                  OBJECT_IDENTIFIER(oid);
  364.                  SEQUENCE {
  365.                          INTEGER(p);
  366.                          INTEGER(q);
  367.                          INTEGER(g);
  368.                  }
  369. }
  370. // subject public key
  371. BIT_STRING(pub);
  372.         }
  373. retval = asn1_der_decode_integer(pub, y);
  374.         return (retval);
  375. }
  376. Bstream
  377. asn1_der_encode_dsa_publickey(Bigint& p, Bigint& q, Bigint& g, Bigint& y)
  378. {
  379. Bstream tmpstr;
  380. ObjId keyoid = dsa;
  381. // params
  382. tmpstr = asn1_der_encode_sequence(
  383. asn1_der_encode_integer(p) +
  384. asn1_der_encode_integer(q) +
  385. asn1_der_encode_integer(g));
  386. // subject public key alg id
  387. tmpstr = keyoid.encode() + tmpstr;
  388. tmpstr = asn1_der_encode_sequence(tmpstr);
  389. // subject public key info
  390. tmpstr = asn1_der_encode_sequence(tmpstr +
  391. asn1_der_encode_bit_string(
  392. asn1_der_encode_integer(y)));
  393. return (tmpstr);
  394. }
  395. /*
  396.  * Generate a bignum of a specified length, with the given
  397.  * high and low 8 bits. "High" is merged into the high 8 bits of the
  398.  * number.  For example, set it to 0x80 to ensure that the number is
  399.  * exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
  400.  * "Low" is merged into the low 8 bits.  For example, set it to
  401.  * 1 to ensure that you generate an odd number.
  402.  *
  403.  * Then XOR the result into the input bignum.  This is to
  404.  * accomodate the kosherizer in all its generality.
  405.  *
  406.  * The bignum is generated using the given seed string.  The
  407.  * technique is from David Kravitz (of the NSA)'s "kosherizer".
  408.  * The string is hashed, and that (with the low bit forced to 1)
  409.  * is used for the low 160 bits of the number.  Then the string,
  410.  * considered as a big-endian array of bytes, is incremented
  411.  * and the incremented value is hashed to produce the next most
  412.  * significant 160 bits, and so on.  The increment is performed
  413.  * modulo the size of the seed string.
  414.  *
  415.  * The seed is returned incremented so that it may be used to generate
  416.  * subsequent numbers.
  417.  *
  418.  * The most and least significant 8 bits of the returned number are forced
  419.  * to the values passed in "high" and "low", respectively.  Typically,
  420.  * high would be set to 0x80 to force the most significant bit to 1.
  421.  */
  422. int
  423. genKosherBn(struct BigNum *bn, unsigned bits, unsigned char high,
  424. unsigned char low, unsigned char *seed, unsigned len)
  425. {
  426. unsigned char buf1[SHA_DIGESTSIZE];
  427. unsigned char buf2[SHA_DIGESTSIZE];
  428. unsigned bytes = (bits+7)/8;
  429. unsigned l = 0; /* Current position */
  430. unsigned i;
  431. struct SHAContext sha;
  432. if (!bits)
  433. return 0;
  434. /* Generate the first bunch of hashed data */
  435. shaInit(&sha);
  436. shaUpdate(&sha, seed, len);
  437. shaFinal(&sha, buf1);
  438. /* Increment the seed, ignoring carry out. */
  439. i = len;
  440. while (i-- && (++seed[i] & 255) == 0)
  441. ;
  442. /* XOR in the existing bytes */
  443. bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
  444. for (i = 0; i < SHA_DIGESTSIZE; i++)
  445. buf1[i] ^= buf2[i];
  446. buf1[SHA_DIGESTSIZE-1] |= low;
  447. while (bytes > SHA_DIGESTSIZE) {
  448. bytes -= SHA_DIGESTSIZE;
  449. /* Merge in low half of high bits, if necessary */
  450. if (bytes == 1 && (bits & 7))
  451. buf1[0] |= high << (bits & 7);
  452. if (bnInsertBigBytes(bn, buf1, l, SHA_DIGESTSIZE) < 0)
  453. return -1;
  454. l += SHA_DIGESTSIZE;
  455. /* Compute the next hash we need */
  456. shaInit(&sha);
  457. shaUpdate(&sha, seed, len);
  458. shaFinal(&sha, buf1);
  459. /* Increment the seed, ignoring carry out. */
  460. i = len;
  461. while (i-- && (++seed[i] & 255) == 0)
  462. ;
  463. /* XOR in the existing bytes */
  464. bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
  465. for (i = 0; i < SHA_DIGESTSIZE; i++)
  466. buf1[i] ^= buf2[i];
  467. }
  468. /* Do the final "bytes"-long section, using the tail bytes in buf1 */
  469. /* Mask off excess high bits */
  470. buf1[SHA_DIGESTSIZE-bytes] &= 255 >> (-bits & 7);
  471. /* Merge in specified high bits */
  472. buf1[SHA_DIGESTSIZE-bytes] |= high >> (-bits & 7);
  473. if (bytes > 1 && (bits & 7))
  474. buf1[SHA_DIGESTSIZE-bytes+1] |= high << (bits & 7);
  475. /* Merge in the appropriate bytes of the buffer */
  476. if (bnInsertBigBytes(bn, buf1+SHA_DIGESTSIZE-bytes, l, bytes) < 0)
  477. return -1;
  478. return 0;
  479. }
  480. /* Context for printing progress dots on the screen. */
  481. struct Progress {
  482. FILE *f;
  483. unsigned column, wrap;
  484. };
  485. static int
  486. genProgress(void *arg, int c)
  487. {
  488. struct Progress *p = (struct Progress *)arg;
  489. if (++p->column > p->wrap) {
  490. putc('n', p->f);
  491. p->column = 1;
  492. }
  493. putc(c, p->f);
  494. fflush(p->f);
  495. return 0;
  496. }
  497. int
  498. dsaGen(struct BigNum *p, unsigned pbits, struct BigNum *q, unsigned qbits,
  499. struct BigNum *g, struct BigNum *x, struct BigNum *y,
  500. unsigned char *seed, unsigned len, FILE *f)
  501. {
  502. return -1;
  503. }
  504. // returns 0 on success or -1 on failure
  505. int
  506. dsa_newcert(char *certreqFile, char *certFile, int lifetime,
  507. Bstream& passphrase)
  508. {
  509. int retval;
  510. Bstream nullbstr;
  511. PubKey pub_CA, pub_subject;
  512. AlgId sigalg;
  513. Name issuer, subject;
  514. String errormsg;
  515. sigalg.algid = dsaWithSHA;
  516. camode = TRUE;
  517. Bstream certreq = File_to_Bstr(get_byzantine_dir() + CA_CERTREQ_FILE);
  518.   
  519. if (certreq == nullbstr) {
  520. fprintf(stderr, "Unable to read %sn", CA_CERTREQ_FILE);
  521. return(-1);
  522. }
  523. if (retval = get_certreq_params(certreq, issuer, pub_CA)) {
  524. fprintf(stderr,
  525. "Error in decoding CA certreq file %sn", CA_CERTREQ_FILE);
  526. asn1_perror(retval);
  527. return(retval);
  528. }
  529. if (retval = get_certreq_params(File_to_Bstr(certreqFile), 
  530. subject, pub_subject)) {
  531. fprintf(stderr,
  532. "Error in decoding subject certreq file %sn",
  533. certreqFile);
  534. asn1_perror(retval);
  535. return(retval);
  536. }
  537. // check if a certificate is already issued for
  538. // this subject and public key
  539. if (allow_certification(subject, pub_subject) == BOOL_FALSE) {
  540. fprintf(stderr,
  541. "Cannot issue a certificate for this request.n");
  542. return(-1);
  543. }
  544. PCTime notbefore = timenow();
  545. GMtime gtime = notbefore.get();
  546. gtime.year += lifetime / 12; // lifetime is in months
  547. gtime.month += lifetime % 12; // 0 - 11 months
  548. if (gtime.month > 12) {
  549. gtime.year += gtime.month / 12;
  550. gtime.month = gtime.month % 12; // 1 - 11 months
  551. }
  552. PCTime notafter(gtime);
  553. // XXX Change for HW signer
  554. Bstream priv_CA;
  555. // Bstream priv_CA = getCAprivkey(passphrase, errormsg);
  556. // if (priv_CA == nullbstr) {
  557. // fprintf(stderr, "Error: %sn", (const char *)errormsg);
  558. // fprintf(stderr,
  559. // "Unable to fetch CA private key, certificate not createdn");
  560. // return(-1);
  561. // }
  562. Bigint serialnum = getSerialnum();
  563. X509Cert cert(serialnum, sigalg, issuer, notbefore, notafter, subject,
  564. pub_subject);
  565. Bstream bercert = cert.sign_and_encode(priv_CA);
  566. // Verify the signature on certificate
  567. VerifyResult result = cert.verify(pub_CA);
  568. if (result != VALID) {
  569. fprintf(stderr, "Error in creating new certificate.n");
  570. return(-1);
  571. }
  572. String certfilename = get_byzantine_dir() + (String)CERT_DATABASE_DIR +
  573. DIR_MARKER + serialnum.getnumstr();
  574.   
  575. bercert.store(certfilename); // Fix for decimal # use XXX
  576. bercert.store(certFile); // Fix for decimal # use XXX
  577. String temp;
  578. temp = serialnum.getnumstrd();
  579. fprintf(stderr, "Succesfully created valid certificate # ");
  580. fprintf(stderr, "%sn", (const char *)temp);
  581. return(0);
  582. }