FreeRDP/winpr/tools/makecert/makecert.c
2015-06-22 19:31:25 +02:00

1126 lines
26 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* WinPR: Windows Portable Runtime
* makecert replacement
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/cmdline.h>
#include <winpr/sysinfo.h>
#include <openssl/conf.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/x509v3.h>
#include <winpr/tools/makecert.h>
struct _MAKECERT_CONTEXT
{
int argc;
char** argv;
RSA* rsa;
X509* x509;
EVP_PKEY* pkey;
PKCS12* pkcs12;
BOOL live;
BOOL silent;
BOOL crtFormat;
BOOL pemFormat;
BOOL pfxFormat;
char* password;
char* output_file;
char* output_path;
char* default_name;
char* common_name;
int duration_years;
int duration_months;
};
COMMAND_LINE_ARGUMENT_A args[] =
{
/* Custom Options */
{ "rdp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Generate certificate with required options for RDP usage."
},
{ "silent", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Silently generate certificate without verbose output."
},
{ "live", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Generate certificate live in memory when used as a library."
},
{ "format", COMMAND_LINE_VALUE_REQUIRED, "<crt|pem|pfx>", NULL, NULL, -1, NULL,
"Specify certificate file format"
},
{ "path", COMMAND_LINE_VALUE_REQUIRED, "<path>", NULL, NULL, -1, NULL,
"Specify certificate file output path"
},
{ "p", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL,
"Specify certificate export password"
},
/* Basic Options */
{ "n", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL,
"Specifies the subject's certificate name. This name must conform to the X.500 standard. "
"The simplest method is to specify the name in double quotes, preceded by CN=; for example, -n \"CN=myName\"."
},
{ "pe", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Marks the generated private key as exportable. This allows the private key to be included in the certificate."
},
{ "sk", COMMAND_LINE_VALUE_REQUIRED, "<keyname>", NULL, NULL, -1, NULL,
"Specifies the subject's key container location, which contains the private key. "
"If a key container does not exist, it will be created."
},
{ "sr", COMMAND_LINE_VALUE_REQUIRED, "<location>", NULL, NULL, -1, NULL,
"Specifies the subject's certificate store location. location can be either currentuser (the default) or localmachine."
},
{ "ss", COMMAND_LINE_VALUE_REQUIRED, "<store>", NULL, NULL, -1, NULL,
"Specifies the subject's certificate store name that stores the output certificate."
},
{ "#", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Specifies a serial number from 1 to 2,147,483,647. The default is a unique value generated by Makecert.exe."
},
{ "$", COMMAND_LINE_VALUE_REQUIRED, "<authority>", NULL, NULL, -1, NULL,
"Specifies the signing authority of the certificate, which must be set to either commercial "
"(for certificates used by commercial software publishers) or individual (for certificates used by individual software publishers)."
},
/* Extended Options */
{ "a", COMMAND_LINE_VALUE_REQUIRED, "<algorithm>", NULL, NULL, -1, NULL,
"Specifies the signature algorithm. algorithm must be md5, sha1 (the default), sha256, sha384, or sha512."
},
{ "b", COMMAND_LINE_VALUE_REQUIRED, "<mm/dd/yyyy>", NULL, NULL, -1, NULL,
"Specifies the start of the validity period. Defaults to the current date."
},
{ "crl", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Generates a certificate relocation list (CRL) instead of a certificate."
},
{ "cy", COMMAND_LINE_VALUE_REQUIRED, "<certType>", NULL, NULL, -1, NULL,
"Specifies the certificate type. Valid values are end for end-entity and authority for certification authority."
},
{ "e", COMMAND_LINE_VALUE_REQUIRED, "<mm/dd/yyyy>", NULL, NULL, -1, NULL,
"Specifies the end of the validity period. Defaults to 12/31/2039 11:59:59 GMT."
},
{ "eku", COMMAND_LINE_VALUE_REQUIRED, "<oid[,oid…]>", NULL, NULL, -1, NULL,
"Inserts a list of comma-separated, enhanced key usage object identifiers (OIDs) into the certificate."
},
{ "h", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Specifies the maximum height of the tree below this certificate."
},
{ "ic", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL,
"Specifies the issuer's certificate file."
},
{ "ik", COMMAND_LINE_VALUE_REQUIRED, "<keyName>", NULL, NULL, -1, NULL,
"Specifies the issuer's key container name."
},
{ "iky", COMMAND_LINE_VALUE_REQUIRED, "<keyType>", NULL, NULL, -1, NULL,
"Specifies the issuer's key type, which must be one of the following: "
"signature (which indicates that the key is used for a digital signature), "
"exchange (which indicates that the key is used for key encryption and key exchange), "
"or an integer that represents a provider type. "
"By default, you can pass 1 for an exchange key or 2 for a signature key."
},
{ "in", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL,
"Specifies the issuer's certificate common name."
},
{ "ip", COMMAND_LINE_VALUE_REQUIRED, "<provider>", NULL, NULL, -1, NULL,
"Specifies the issuer's CryptoAPI provider name. For information about the CryptoAPI provider name, see the sp option."
},
{ "ir", COMMAND_LINE_VALUE_REQUIRED, "<location>", NULL, NULL, -1, NULL,
"Specifies the location of the issuer's certificate store. location can be either currentuser (the default) or localmachine."
},
{ "is", COMMAND_LINE_VALUE_REQUIRED, "<store>", NULL, NULL, -1, NULL,
"Specifies the issuer's certificate store name."
},
{ "iv", COMMAND_LINE_VALUE_REQUIRED, "<pvkFile>", NULL, NULL, -1, NULL,
"Specifies the issuer's .pvk private key file."
},
{ "iy", COMMAND_LINE_VALUE_REQUIRED, "<type>", NULL, NULL, -1, NULL,
"Specifies the issuer's CryptoAPI provider type. For information about the CryptoAPI provider type, see the sy option."
},
{ "l", COMMAND_LINE_VALUE_REQUIRED, "<link>", NULL, NULL, -1, NULL,
"Links to policy information (for example, to a URL)."
},
{ "len", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Specifies the generated key length, in bits."
},
{ "m", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Specifies the duration, in months, of the certificate validity period."
},
{ "y", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Specifies the duration, in years, of the certificate validity period."
},
{ "nscp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Includes the Netscape client-authorization extension."
},
{ "r", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"Creates a self-signed certificate."
},
{ "sc", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL,
"Specifies the subject's certificate file."
},
{ "sky", COMMAND_LINE_VALUE_REQUIRED, "<keyType>", NULL, NULL, -1, NULL,
"Specifies the subject's key type, which must be one of the following: "
"signature (which indicates that the key is used for a digital signature), "
"exchange (which indicates that the key is used for key encryption and key exchange), "
"or an integer that represents a provider type. "
"By default, you can pass 1 for an exchange key or 2 for a signature key."
},
{ "sp", COMMAND_LINE_VALUE_REQUIRED, "<provider>", NULL, NULL, -1, NULL,
"Specifies the subject's CryptoAPI provider name, which must be defined in the registry subkeys of "
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider. If both sp and sy are present, "
"the type of the CryptoAPI provider must correspond to the Type value of the provider's subkey."
},
{ "sv", COMMAND_LINE_VALUE_REQUIRED, "<pvkFile>", NULL, NULL, -1, NULL,
"Specifies the subject's .pvk private key file. The file is created if none exists."
},
{ "sy", COMMAND_LINE_VALUE_REQUIRED, "<type>", NULL, NULL, -1, NULL,
"Specifies the subject's CryptoAPI provider type, which must be defined in the registry subkeys of "
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider Types. If both sy and sp are present, "
"the name of the CryptoAPI provider must correspond to the Name value of the provider type subkey."
},
{ "tbs", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL,
"Specifies the certificate or CRL file to be signed."
},
/* Help */
{ "?", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "help", "print help" },
{ "!", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "help-ext", "print extended help" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
int makecert_print_command_line_help(int argc, char** argv)
{
char* str;
int length;
COMMAND_LINE_ARGUMENT_A* arg;
printf("Usage: %s [options] [output file]\n", argv[0]);
printf("\n");
arg = args;
do
{
if (arg->Flags & COMMAND_LINE_VALUE_FLAG)
{
printf(" %s", "-");
printf("%-20s", arg->Name);
printf("\t%s\n", arg->Text);
}
else if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) || (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL))
{
printf(" %s", "-");
if (arg->Format)
{
length = strlen(arg->Name) + strlen(arg->Format) + 2;
str = malloc(length + 1);
if (!str)
return -1;
sprintf_s(str, length + 1, "%s %s", arg->Name, arg->Format);
printf("%-20s", str);
free(str);
}
else
{
printf("%-20s", arg->Name);
}
printf("\t%s\n", arg->Text);
}
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return 1;
}
int x509_add_ext(X509* cert, int nid, char* value)
{
X509V3_CTX ctx;
X509_EXTENSION* ext;
X509V3_set_ctx_nodb(&ctx);
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
ext = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ext)
return 0;
X509_add_ext(cert, ext, -1);
X509_EXTENSION_free(ext);
return 1;
}
char* x509_name_parse(char* name, char* txt, int* length)
{
char* p;
char* entry;
p = strstr(name, txt);
if (!p)
return NULL;
entry = p + strlen(txt) + 1;
p = strchr(entry, '=');
if (!p)
*length = strlen(entry);
else
*length = p - entry;
return entry;
}
char* x509_get_default_name()
{
CHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD nSize = MAX_COMPUTERNAME_LENGTH;
char* ret;
if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
return NULL;
ret = _strdup(computerName);
if (!ret)
return NULL;
return ret;
}
int command_line_pre_filter(MAKECERT_CONTEXT* context, int index, int argc, LPCSTR* argv)
{
if (index == (argc - 1))
{
if (argv[index][0] != '-')
context->output_file = (char*) argv[index];
return 1;
}
return 0;
}
int makecert_context_parse_arguments(MAKECERT_CONTEXT* context, int argc, char** argv)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
/**
* makecert -r -pe -n "CN=%COMPUTERNAME%" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr LocalMachine
* -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
*/
CommandLineClearArgumentsA(args);
flags = COMMAND_LINE_SEPARATOR_SPACE | COMMAND_LINE_SIGIL_DASH;
status = CommandLineParseArgumentsA(argc, (const char**) argv, args, flags, context,
(COMMAND_LINE_PRE_FILTER_FN_A) command_line_pre_filter, NULL);
if (status & COMMAND_LINE_STATUS_PRINT_HELP)
{
makecert_print_command_line_help(argc, argv);
return 0;
}
arg = args;
do
{
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
/* Basic Options */
CommandLineSwitchCase(arg, "silent")
{
context->silent = TRUE;
}
CommandLineSwitchCase(arg, "live")
{
context->live = TRUE;
}
CommandLineSwitchCase(arg, "format")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
if (strcmp(arg->Value, "crt") == 0)
{
context->crtFormat = TRUE;
context->pemFormat = FALSE;
context->pfxFormat = FALSE;
}
else if (strcmp(arg->Value, "pem") == 0)
{
context->crtFormat = FALSE;
context->pemFormat = TRUE;
context->pfxFormat = FALSE;
}
else if (strcmp(arg->Value, "pfx") == 0)
{
context->crtFormat = FALSE;
context->pemFormat = FALSE;
context->pfxFormat = TRUE;
}
else
return -1;
}
CommandLineSwitchCase(arg, "path")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
context->output_path = _strdup(arg->Value);
if (!context->output_path)
return -1;
}
CommandLineSwitchCase(arg, "p")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
context->password = _strdup(arg->Value);
if (!context->password)
return -1;
}
CommandLineSwitchCase(arg, "n")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
context->common_name = _strdup(arg->Value);
if (!context->common_name)
return -1;
}
CommandLineSwitchCase(arg, "y")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
context->duration_years = atoi(arg->Value);
}
CommandLineSwitchCase(arg, "m")
{
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
continue;
context->duration_months = atoi(arg->Value);
}
CommandLineSwitchDefault(arg)
{
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return 1;
}
int makecert_context_set_output_file_name(MAKECERT_CONTEXT* context, char* name)
{
free(context->output_file);
context->output_file = _strdup(name);
if (!context->output_file)
return -1;
return 1;
}
int makecert_context_output_certificate_file(MAKECERT_CONTEXT* context, char* path)
{
FILE* fp = NULL;
int status;
int length;
int offset;
char* filename = NULL;
char* fullpath = NULL;
int ret = -1;
BIO* bio = NULL;
BYTE* x509_str = NULL;
if (!context->output_file)
{
context->output_file = _strdup(context->default_name);
if (!context->output_file)
return -1;
}
/*
* Output Certificate File
*/
length = strlen(context->output_file);
filename = malloc(length + 8);
if (!filename)
return -1;
strcpy(filename, context->output_file);
if (context->crtFormat)
strcpy(&filename[length], ".crt");
else if (context->pemFormat)
strcpy(&filename[length], ".pem");
else if (context->pfxFormat)
strcpy(&filename[length], ".pfx");
if (path)
fullpath = GetCombinedPath(path, filename);
else
fullpath = _strdup(filename);
if (!fullpath)
goto out_fail;
fp = fopen(fullpath, "w+");
if (fp)
{
if (context->pfxFormat)
{
if (!context->password)
{
context->password = _strdup("password");
if (!context->password)
goto out_fail;
printf("Using default export password \"password\"\n");
}
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
context->pkcs12 = PKCS12_create(context->password, context->default_name,
context->pkey, context->x509, NULL, 0, 0, 0, 0, 0);
if (!context->pkcs12)
goto out_fail;
bio = BIO_new(BIO_s_mem());
if (!bio)
goto out_fail;
status = i2d_PKCS12_bio(bio, context->pkcs12);
if (status != 1)
goto out_fail;
offset = 0;
length = 2048;
x509_str = (BYTE*) malloc(length);
if (!x509_str)
goto out_fail;
status = BIO_read(bio, x509_str, length);
if (status < 0)
goto out_fail;
offset += status;
while (offset >= length)
{
int new_len;
BYTE *new_str;
new_len = length * 2;
new_str = (BYTE*) realloc(x509_str, new_len);
if (!new_str)
{
status = -1;
break;
}
length = new_len;
x509_str = new_str;
status = BIO_read(bio, &x509_str[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
goto out_fail;
length = offset;
fwrite((void*) x509_str, length, 1, fp);
}
else
{
bio = BIO_new(BIO_s_mem());
if (!bio)
goto out_fail;
if (!PEM_write_bio_X509(bio, context->x509))
goto out_fail;
offset = 0;
length = 2048;
x509_str = (BYTE*) malloc(length);
if (!x509_str)
goto out_fail;
status = BIO_read(bio, x509_str, length);
if (status < 0)
goto out_fail;
offset += status;
while (offset >= length)
{
int new_len;
BYTE *new_str;
new_len = length * 2;
new_str = (BYTE*) realloc(x509_str, new_len);
if (!new_str)
{
status = -1;
break;
}
length = new_len;
x509_str = new_str;
status = BIO_read(bio, &x509_str[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
goto out_fail;
length = offset;
fwrite((void*) x509_str, length, 1, fp);
free(x509_str);
x509_str = NULL;
BIO_free(bio);
bio = NULL;
if (context->pemFormat)
{
bio = BIO_new(BIO_s_mem());
if (!bio)
goto out_fail;
status = PEM_write_bio_PrivateKey(bio, context->pkey, NULL, NULL, 0, NULL, NULL);
offset = 0;
length = 2048;
if (!(x509_str = (BYTE*) malloc(length)))
goto out_fail;
status = BIO_read(bio, x509_str, length);
if (status < 0)
goto out_fail;
offset += status;
while (offset >= length)
{
int new_len;
BYTE *new_str;
new_len = length * 2;
new_str = (BYTE*) realloc(x509_str, new_len);
if (!new_str)
{
status = -1;
break;
}
length = new_len;
x509_str = new_str;
status = BIO_read(bio, &x509_str[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
goto out_fail;
length = offset;
fwrite((void*) x509_str, length, 1, fp);
}
}
}
ret = 1;
out_fail:
if (bio)
BIO_free(bio);
if (fp)
fclose(fp);
free(x509_str);
free(filename);
free(fullpath);
return ret;
}
int makecert_context_output_private_key_file(MAKECERT_CONTEXT* context, char* path)
{
FILE* fp;
int status;
int length;
int offset;
char* filename;
char* fullpath;
if (!context->crtFormat)
return 1;
if (!context->output_file)
context->output_file = context->default_name;
/**
* Output Private Key File
*/
length = strlen(context->output_file);
filename = malloc(length + 8);
if (!filename)
return -1;
strcpy(filename, context->output_file);
strcpy(&filename[length], ".key");
length = strlen(filename);
if (path)
fullpath = GetCombinedPath(path, filename);
else
fullpath = _strdup(filename);
if (!fullpath)
{
free(filename);
return -1;
}
fp = fopen(fullpath, "w+");
if (fp)
{
BIO* bio;
BYTE* x509_str;
bio = BIO_new(BIO_s_mem());
if (!bio)
{
free (filename);
free(fullpath);
fclose(fp);
return -1;
}
status = PEM_write_bio_PrivateKey(bio, context->pkey, NULL, NULL, 0, NULL, NULL);
offset = 0;
length = 2048;
x509_str = (BYTE*) malloc(length);
if (!x509_str)
{
free (filename);
free(fullpath);
fclose(fp);
return -1;
}
status = BIO_read(bio, x509_str, length);
if (status < 0)
{
free (filename);
free(fullpath);
fclose(fp);
return -1;
}
offset += status;
while (offset >= length)
{
int new_len;
BYTE *new_str;
new_len = length * 2;
new_str = (BYTE*) realloc(x509_str, new_len);
if (!new_str)
{
status = -1;
break;
}
length = new_len;
x509_str = new_str;
status = BIO_read(bio, &x509_str[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
{
free (filename);
free(fullpath);
fclose(fp);
return -1;
}
length = offset;
fwrite((void*) x509_str, length, 1, fp);
free(x509_str);
BIO_free(bio);
fclose(fp);
}
free(filename);
free(fullpath);
return 1;
}
int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv)
{
int length;
char* entry;
int key_length;
long serial = 0;
X509_NAME* name = NULL;
const EVP_MD* md = NULL;
COMMAND_LINE_ARGUMENT_A* arg;
int ret;
ret = makecert_context_parse_arguments(context, argc, argv);
if (ret < 1)
return ret;
if (!context->default_name && !context->common_name)
{
context->default_name = x509_get_default_name();
if (!context->default_name)
return -1;
}
else
{
context->default_name = _strdup(context->common_name);
if (!context->default_name)
return -1;
}
if (!context->common_name)
{
context->common_name = _strdup(context->default_name);
if (!context->common_name)
return -1;
}
if (!context->pkey)
context->pkey = EVP_PKEY_new();
if (!context->pkey)
return -1;
if (!context->x509)
context->x509 = X509_new();
if (!context->x509)
return -1;
key_length = 2048;
arg = CommandLineFindArgumentA(args, "len");
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
key_length = atoi(arg->Value);
}
context->rsa = RSA_generate_key(key_length, RSA_F4, NULL, NULL);
if (!EVP_PKEY_assign_RSA(context->pkey, context->rsa))
return -1;
context->rsa = NULL;
X509_set_version(context->x509, 2);
arg = CommandLineFindArgumentA(args, "#");
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
serial = atoi(arg->Value);
else
serial = (long) GetTickCount64();
ASN1_INTEGER_set(X509_get_serialNumber(context->x509), serial);
X509_gmtime_adj(X509_get_notBefore(context->x509), 0);
if (context->duration_months)
{
X509_gmtime_adj(X509_get_notAfter(context->x509), (long) (60 * 60 * 24 * 31 * context->duration_months));
}
else if (context->duration_years)
{
X509_gmtime_adj(X509_get_notAfter(context->x509), (long) (60 * 60 * 24 * 365 * context->duration_years));
}
X509_set_pubkey(context->x509, context->pkey);
name = X509_get_subject_name(context->x509);
arg = CommandLineFindArgumentA(args, "n");
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
entry = x509_name_parse(arg->Value, "C", &length);
if (entry)
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
entry = x509_name_parse(arg->Value, "ST", &length);
if (entry)
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
entry = x509_name_parse(arg->Value, "L", &length);
if (entry)
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
entry = x509_name_parse(arg->Value, "O", &length);
if (entry)
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
entry = x509_name_parse(arg->Value, "OU", &length);
if (entry)
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
entry = context->common_name;
length = strlen(entry);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
}
else
{
entry = context->common_name;
length = strlen(entry);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0);
}
X509_set_issuer_name(context->x509, name);
x509_add_ext(context->x509, NID_ext_key_usage, "serverAuth");
x509_add_ext(context->x509, NID_key_usage, "keyEncipherment,dataEncipherment");
arg = CommandLineFindArgumentA(args, "a");
md = EVP_sha1();
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
if (strcmp(arg->Value, "md5") == 0)
md = EVP_md5();
else if (strcmp(arg->Value, "sha1") == 0)
md = EVP_sha1();
else if (strcmp(arg->Value, "sha256") == 0)
md = EVP_sha256();
else if (strcmp(arg->Value, "sha384") == 0)
md = EVP_sha384();
else if (strcmp(arg->Value, "sha512") == 0)
md = EVP_sha512();
}
if (!X509_sign(context->x509, context->pkey, md))
return -1;
/**
* Print certificate
*/
if (!context->silent)
{
BIO* bio;
int status;
int length;
int offset;
BYTE* x509_str;
bio = BIO_new(BIO_s_mem());
if (!bio)
return -1;
status = X509_print(bio, context->x509);
offset = 0;
length = 2048;
if (!(x509_str = (BYTE*) malloc(length + 1)))
{
BIO_free(bio);
return -1;
}
status = BIO_read(bio, x509_str, length);
if (status < 0)
{
BIO_free(bio);
free(x509_str);
return -1;
}
offset += status;
while (offset >= length)
{
int new_len;
BYTE *new_str;
new_len = length * 2;
new_str = (BYTE*) realloc(x509_str, new_len);
if (!new_str)
{
status = -1;
break;
}
length = new_len;
x509_str = new_str;
status = BIO_read(bio, &x509_str[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
return -1;
length = offset;
x509_str[length] = '\0';
printf("%s", x509_str);
free(x509_str);
BIO_free(bio);
}
/**
* Output certificate and private key to files
*/
if (!context->live)
{
makecert_context_output_certificate_file(context, context->output_path);
if (context->crtFormat)
makecert_context_output_private_key_file(context, context->output_path);
}
return 0;
}
MAKECERT_CONTEXT* makecert_context_new()
{
MAKECERT_CONTEXT* context = NULL;
context = (MAKECERT_CONTEXT*) calloc(1, sizeof(MAKECERT_CONTEXT));
if (context)
{
context->crtFormat = TRUE;
context->duration_years = 1;
}
return context;
}
void makecert_context_free(MAKECERT_CONTEXT* context)
{
if (context)
{
free(context->password);
X509_free(context->x509);
EVP_PKEY_free(context->pkey);
free(context->default_name);
free(context->common_name);
free(context->output_file);
free(context->output_path);
CRYPTO_cleanup_all_ex_data();
free(context);
}
}