?? simpleca.c
字號:
} if(strcmp(left, "ext-key-usage")==0) { process_semicolonlist(&ext_usage, right); return; } if(strcmp(left, "key-size")==0) { keysize = atoi(right); if(keysize<=0) die("Illegal key size."); return; } if(strcmp(left, "password")==0) { password = right; return; } if(strcmp(left, "start-date")==0) { validfrom = process_date(right); return; } if(strcmp(left, "end-date")==0) { validto = process_date(right); return; } if(strcmp(left, "crl-next-update")==0) { crl_next_update = process_date(right); return; } if(strcmp(left, "crldp")==0) { crldp = right; return; } if(strcmp(left, "view")==0) { inputfile = right; check_no_action(); action = ACTION_VIEW; return; } if(strcmp(left, "priv-key")==0) { keyfile = right; return; } if(strcmp(left, "crl-contents")==0) { if(inputfile) { die("Input file already specified."); } inputfile = right; return; } if(strcmp(left, "request")==0) { inputfile = right; return; } if(strcmp(left, "create-new-ca")==0) { outputfile = right; check_no_action(); action = ACTION_CREATECA; return; } if(strcmp(left, "create-keys")==0) { outputfile = right; check_no_action(); action = ACTION_CREATEKEYS; return; } if(strcmp(left, "create-request")==0) { outputfile = right; check_no_action(); action = ACTION_CREATEREQUEST; return; } if(strcmp(left, "create-cert")==0) { outputfile = right; check_no_action(); action = ACTION_CREATECERT; return; } if(strcmp(left, "create-crl")==0) { outputfile = right; check_no_action(); action = ACTION_CREATECRL; return; } if(strcmp(left, "cert-dup-dir")==0) { cert_dup_dir = right; return; } fprintf(stderr, "ERROR: Unrecognized command line option \"%s\" with argument\n", left); print_help_text(); exit(EXIT_FAILURE);}/* Process a singleton option (an option with no equals sign). */void process_singleton(char *val){ if(strcmp(val, "show-values")==0) { show_values = TRUE; return; } if(strcmp(val, "version")==0) { print_version_info(); exit(EXIT_SUCCESS); } if(strcmp(val, "values")==0) { check_no_action(); action = ACTION_VALUES; return; } if(strcmp(val, "help")==0 || strcmp(val, "-help")==0 || strcmp(val, "--help")==0 || strcmp(val, "-?")==0 || strcmp(val, "/h")==0 ) { print_version_info(); print_help_text(); exit(EXIT_SUCCESS); } fprintf(stderr, "ERROR: Unrecognized singleton command line option \"%s\".\n", val); exit(EXIT_FAILURE);}/* Given a certificate and list of strings, interpret the list of strings as subject information and set it in the certificate. The strings must start with subject field names like "cn", then have a colon, then the data.*//* Take a DN string from cryptlib in the format: cn=Nathan\, Inc., o=Whitehead and Sons, c=US Return a nice SimpleCA formatted string with the same info. cn:Nathan, Inc.;o:Whitehead and Sons*/char *prettify_subject(char *subj){ char *t; /* First substitute colons for equals signs (but not escaped equals) */ t=subj; while((t=strchr(t, '='))) if(*(t-1)!='\\') *t=':'; else { /* For escaped equals, unescape. */ *(t-1)='='; memmove(t, t+1, strlen(t)); t++; } /* Next substitute semicolons for commas (but not escaped commas) */ t=subj; while((t=strchr(t, ','))) if(*(t-1)!='\\') *t=';'; else { /* What do we do if we get an escaped comma? Unescape it. */ *(t-1)=','; memmove(t, t+1, strlen(t)); t++; } return subj;}void set_cert_dn(CRYPT_CERTIFICATE cert, struct stringlist *subj, char *request_info){ int res; char *data, *result; char *left, *right, *p; struct stringlist *ptr; result = ""; result = string_cat(result, request_info); if(strlen(request_info)>0) result = string_cat(result, ", "); for(ptr = subj; ptr; ptr = ptr->next) { data = ptr->item; p=strchr(data, ':'); if(!p) { fprintf(stderr, "ERROR: Could not find colon in %s.\n", data); exit(EXIT_FAILURE); } *p=0; left=data; right=p+1; result = string_cat(result, left); result = string_cat(result, "="); result = string_cat(result, right); result = string_cat(result, ", "); } if(result[strlen(result)-2]==',') result[strlen(result)-2]=0; if(strlen(result)>0) { res = cryptSetAttributeString(cert, CRYPT_CERTINFO_DN, result, strlen(result)); if(res) die("Could not set subject name."); } else { /* In this case the subject should be blank */ warn("Empty subject.");#ifdef SET_FAUX_BLANK_SUBJECT res = cryptSetAttributeString(cert, CRYPT_CERTINFO_DN, "cn=[UNUSED]", 11); if(res) die("Could not set faux-blank subject.");#endif }}void set_cert_gn(CRYPT_CERTIFICATE cert, struct stringlist *subj){ int res; char *data; char *left, *right, *p; char buffer[MAXBUF]; struct stringlist *ptr; /* Process in reverse order so later ones get set first (cryptlib does not allow overwriting of already set values) */ stringlist_reverse(&subj); for(ptr = subj; ptr; ptr = ptr->next) { data = ptr->item; p=strchr(data, ':'); if(!p) { fprintf(stderr, "ERROR: Could not find colon in %s.\n", data); exit(EXIT_FAILURE); } *p=0; left=data; right=p+1; /* Now actually interpret the left side */ if(strcasecmp(left, "email")==0) { if(strlen(right)<8) die("Email name must be 8 or more characters long."); res = cryptSetAttributeString(cert, CRYPT_CERTINFO_RFC822NAME, right, strlen(right)); if(res) die("Could not set email name in alt-name."); continue; } if(strcasecmp(left, "dns")==0) { res = cryptSetAttributeString(cert, CRYPT_CERTINFO_DNSNAME, right, strlen(right)); if(res) die("Could not set DNS name in alt-name."); continue; } if(strcasecmp(left, "ip")==0) { int ip0, ip1, ip2, ip3; res = sscanf(right, "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); if(res!=4) die("Bad IP address format in alt-name."); if(ip0<0 || ip1<0 || ip2<0 || ip3<0 || ip0>255 || ip1>255 || ip2>255 || ip3>255) die("Bad IP address format in alt-name."); buffer[0] = ip0; buffer[1] = ip1; buffer[2] = ip2; buffer[3] = ip3; buffer[4] = 0; res = cryptSetAttributeString(cert, CRYPT_CERTINFO_IPADDRESS, buffer, 4); if(res) die("Could not set IP in alt-name."); continue; } fprintf(stderr, "WARNING: Unrecognized subj-alt field %s.\n", left); } stringlist_reverse(&subj);}/* Given a certificate, convert it into a string of characters for output to a file or stdout. */char *export_cert(int cert){ int dataLength, res; char *data; res = cryptExportCert(NULL, &dataLength, CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cert); if(res) die("Certificate export failed."); data = (char *)malloc(dataLength+FUDGE_FACTOR); res = cryptExportCert(data, &dataLength, CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cert); if(res) die("Certificate export failed."); return data;}/* Save a string to a file, but fail if the file already exists. */void save_nooverwrite(char *data, char *filename){ FILE *fp; fp = fopen(filename, "rt"); if(fp) { fclose(fp); die("File already exists."); } fp = fopen(filename, "wt"); if(!fp) die("Unable to create file for writing."); fprintf(fp, "%s", data); fclose(fp);}/* Save a string to a file, but if the file already exists then rename it to a time-stamped backup. */void save_carefully(char *data, char *filename){ FILE *fp; char newfilename[MAXBUF]; struct tm *t; time_t thetime; fp = fopen(filename, "rt"); if(fp) { fclose(fp); thetime = time(NULL); t = localtime(&thetime); snprintf(newfilename, MAXBUF, "%s-%4d-%02d-%02d-%02d-%02d-%02d", filename, t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); fprintf(stderr, "WARNING: Output file %s exists, renaming to %s.\n", filename, newfilename); if(rename(filename, newfilename)) { die("Renaming file failed."); } } fp = fopen(filename, "wt"); if(!fp) die("Could not open file for writing."); fprintf(fp, "%s", data); fclose(fp);}/* Prompt for a password and return the user's answer. */char *get_pass(char *prompt){ char *p;#ifdef WIN32 char buffer[1024]; printf("%s", prompt); fgets(buffer, 1024, stdin); if(strlen(buffer)<MIN_PASSWORD_LENGTH) die("Password is too short."); return strdup(buffer);#else /* getpass() is deprecated, but simple to use */ /* The better UNIX way is to use termios stuff */ p=getpass(prompt); if(strlen(p)<MIN_PASSWORD_LENGTH) die("Password is too short."); return strdup(p);#endif}/* Display prompt and wait for input. */char *prompt(char *txt){ char buffer[BIGMAXBUF]; char *p; printf("%s", txt); fgets(buffer, BIGMAXBUF, stdin); buffer[BIGMAXBUF-1]=0; p=strchr(buffer, '\n'); if(p) *p=0; return strdup(buffer);}/* Given information in the global variables, create a pub/priv keypair and store to a file.*/void create_keys(void){ FILE *fp; CRYPT_KEYSET keyset; CRYPT_CONTEXT privkey; int res; if(!outputfile) die("There must be an output file specified."); fp = fopen(outputfile, "rt"); if(fp) { fclose(fp); die("Output file already exists."); } res = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, outputfile, CRYPT_KEYOPT_CREATE); if(res) die("Creating keyfile failed."); res = cryptCreateContext(&privkey, CRYPT_UNUSED, CRYPT_ALGO_RSA); if(res) die("Creating private key context failed."); res = cryptSetAttributeString(privkey, CRYPT_CTXINFO_LABEL, "private", 7); if(res) die("Setting label for private key failed."); if(keysize<=0) { warn("No keysize specified, using 1024 bits.\n"); keysize = 1024; } res = cryptSetAttribute(privkey, CRYPT_CTXINFO_KEYSIZE, keysize/8); if(res) die("Setting key size failed."); res = cryptGenerateKey(privkey); if(res) die("Generation of private key failed."); if(password==NULL) { password = get_pass("Password for key being created: "); } res = cryptAddPrivateKey(keyset, privkey, password); if(res) die("Adding private key to keyfile failed."); res = cryptKeysetClose(keyset); if(res) die("Closing keyfile failed."); res = cryptDestroyContext(privkey); if(res) die("Freeing private key failed.");}/* Given data in global variables, create a certificate request. */void create_request(void){ CRYPT_KEYSET keyset; CRYPT_CONTEXT privkey; CRYPT_CERTIFICATE cert; char *txt; int res; if(!outputfile) die("There must be an output file specified."); /* fp = fopen(outputfile, "rt"); if(fp) { fclose(fp); die("Output file already exists."); } */ if(keyfile==NULL) die("There must be a private key file specified."); res = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, keyfile, CRYPT_KEYOPT_READONLY); if(res) die("Opening private key file failed."); if(password==NULL) { password = get_pass("Password for private key: "); } res = cryptGetPrivateKey(keyset, &privkey, CRYPT_KEYID_NAME, "private", password); if(res) die("Could not retrieve private key from private key file."); res=cryptCreateCert(&cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTREQUEST); if(res) die("Creation of blank certificate failed."); res=cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, privkey); if(res) die("Could not add public key to certificate request."); res=cryptSetAttribute(cert, CRYPT_CERTINFO_SELFSIGNED, 1); if(res) die("Could not set self-signed attribute for request."); set_cert_dn(cert, subject, ""); set_cert_gn(cert, subject_alt); res=cryptSignCert(cert, privkey); if(res) die("Signing certificate request failed."); txt=export_cert(cert); /* Handle the case when outputfile is STDOUT as a special case and output the text on stdout. */ if(strcmp(outputfile, "STDOUT")==0) { printf("%s\n", txt); } else { save_carefully(txt, outputfile); } if(cert_dup_dir) { char buffer[MAXBUF]; snprintf(buffer, MAXBUF, "%s/%s", cert_dup_dir, outputfile); save_carefully(txt, buffer); } res = cryptDestroyContext(privkey); if(res) die("Freeing private key failed."); res = cryptKeysetClose(keyset); if(res) die("Closing keyfile failed."); res = cryptDestroyCert(cert); if(res) die("Freeing certificate request failed.");}/* Import a certificate from a given filename. If it fails the first time, turn down conformance level.*/CRYPT_CERTIFICATE import_cert(char *filename){ char buffer[BIGMAXBUF]; FILE *fp; int res, length; CRYPT_CERTIFICATE cert; res=cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_STANDARD); if(res) die("Could not set compliance level of Cryptlib."); fp=fopen(filename, "rt"); if(!fp) die("Could not open file for certificate import."); length = fread(buffer, 1, BIGMAXBUF, fp); fclose(fp); res = cryptImportCert(buffer, length, CRYPT_UNUSED, &cert); if(res) { warn("Importing certificate failed at STANDARD compliance level."); res=cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_REDUCED); if(res) die("Could not set compliance level of Cryptlib to reduced."); res = cryptImportCert(buffer, length, CRYPT_UNUSED, &cert); if(res) die("Importing certificate failed at REDUCED compliance level."); } return cert;}/* Given a certificate and two times (as seconds since 1970), set the valid-from and valid-to dates on the certificate.*/void set_cert_valid_times(CRYPT_CERTIFICATE cert, int vfrom, int vto){ char buf[4]; int res; /* Copy the 4 bytes of the integer directly into the buffer. */ memcpy(buf, &vfrom, 4); /* Now consider the buffer as a string of length 4. */ res = cryptSetAttributeString(cert, CRYPT_CERTINFO_VALIDFROM, buf, 4); if(res) die("Could not set valid-from time."); memcpy(buf, &vto, 4); res = cryptSetAttributeString(cert, CRYPT_CERTINFO_VALIDTO, buf, 4); if(res) die("Could not set valid-to time.");}/* Given a certificate and time as seconds since 1970, set the crl-next-update date on the certificate. */void set_crl_next_update(CRYPT_CERTIFICATE cert, int crltime){ char buf[4]; int res; /* Copy the 4 bytes of the integer to the buffer. */ memcpy(buf, &crltime, 4); /* Now consider the buffer as a string of length 4. */ res = cryptSetAttributeString(cert, CRYPT_CERTINFO_NEXTUPDATE, buf, 4); if(res) die("Could not set CRL next-update time.");}/* Given a certificate and list of strings, set the key usage fields on the certificate. */void set_key_usage(CRYPT_CERTIFICATE cert, struct stringlist *usage){ int i, flag; int val, res; struct stringlist *ptr; val = 0; for(ptr = usage; ptr; ptr=ptr->next) { flag = FALSE; for(i=0; i<NUM_USAGE; i++) { if(strcasecmp(ptr->item, usagetable[i].txt)==0) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -