result_t X509Req::sign(const char *issuer, PKey_base *key, v8::Local<v8::Object> opts, obj_ptr<X509Cert_base> &retVal, exlib::AsyncEvent *ac) { result_t hr; bool priv; hr = key->isPrivate(priv); if (hr < 0) return hr; if (!priv) return CHECK_ERROR(CALL_E_INVALIDARG); int ret; std::string subject; pk_context *pk; int32_t hash; std::string buf; obj_ptr<X509Cert> cert; if (!ac) { mpi serial; v8::Local<v8::Value> v; x509write_crt_init(&m_crt); hr = GetConfigValue(opts, "hash", hash); if (hr == CALL_E_PARAMNOTOPTIONAL) hash = m_csr.sig_md; else if (hr < 0) goto exit; if (hash < POLARSSL_MD_MD2 || hash > POLARSSL_MD_RIPEMD160) { hr = CALL_E_INVALIDARG; goto exit; } x509write_crt_set_md_alg(&m_crt, POLARSSL_MD_SHA1); v = opts->Get(v8::String::NewFromUtf8(isolate, "serial", v8::String::kNormalString, 6)); if (!IsEmpty(v)) { v8::String::Utf8Value str(v); if (!*str) { hr = CHECK_ERROR(_ssl::setError(POLARSSL_ERR_MPI_BAD_INPUT_DATA)); goto exit; } mpi_init(&serial); ret = mpi_read_string(&serial, 10, *str); if (ret != 0) { mpi_free(&serial); hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } } else { mpi_init(&serial); mpi_lset(&serial, 1); } ret = x509write_crt_set_serial(&m_crt, &serial); if (ret != 0) { mpi_free(&serial); hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } mpi_free(&serial); date_t d1, d2; std::string s1, s2; hr = GetConfigValue(opts, "notBefore", d1); if (hr == CALL_E_PARAMNOTOPTIONAL) d1.now(); else if (hr < 0) goto exit; d1.toX509String(s1); hr = GetConfigValue(opts, "notAfter", d2); if (hr == CALL_E_PARAMNOTOPTIONAL) { d2 = d1; d2.add(1, date_t::_YEAR); } else if (hr < 0) goto exit; d2.toX509String(s2); ret = x509write_crt_set_validity(&m_crt, s1.c_str(), s2.c_str()); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } bool is_ca = false; hr = GetConfigValue(opts, "ca", is_ca); if (hr < 0 && hr != CALL_E_PARAMNOTOPTIONAL) goto exit; int32_t pathlen = -1; hr = GetConfigValue(opts, "pathlen", pathlen); if (hr < 0 && hr != CALL_E_PARAMNOTOPTIONAL) goto exit; if (pathlen < -1 || pathlen > 127) { hr = CALL_E_INVALIDARG; goto exit; } ret = x509write_crt_set_basic_constraints(&m_crt, is_ca ? 1 : 0, pathlen); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } int key_usage = parseString(opts->Get(v8::String::NewFromUtf8(isolate, "usage", v8::String::kNormalString, 5)), X509Cert::g_usages); if (key_usage < 0) { hr = key_usage; goto exit; } else if (key_usage) { ret = x509write_crt_set_key_usage(&m_crt, key_usage); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } } int cert_type = parseString(opts->Get(v8::String::NewFromUtf8(isolate, "type", v8::String::kNormalString, 4)), X509Cert::g_types); if (cert_type < 0) { hr = cert_type; goto exit; } else if (cert_type) { ret = x509write_crt_set_ns_cert_type(&m_crt, cert_type); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } } return CHECK_ERROR(CALL_E_NOSYNC); } pk = &((PKey *)key)->m_key; x509write_crt_set_subject_key(&m_crt, &m_csr.pk); x509write_crt_set_issuer_key(&m_crt, pk); hr = X509Req::get_subject(subject); if (hr < 0) goto exit; ret = x509write_crt_set_subject_name(&m_crt, subject.c_str()); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } ret = x509write_crt_set_issuer_name(&m_crt, issuer); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } ret = x509write_crt_set_subject_key_identifier(&m_crt); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } ret = x509write_crt_set_authority_key_identifier(&m_crt); if (ret != 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } buf.resize(pk_get_size(pk) * 8 + 128); ret = x509write_crt_pem(&m_crt, (unsigned char *)&buf[0], buf.length(), ctr_drbg_random, &g_ssl.ctr_drbg); if (ret < 0) { hr = CHECK_ERROR(_ssl::setError(ret)); goto exit; } cert = new X509Cert(); hr = cert->load(buf.c_str()); if (hr < 0) goto exit; retVal = cert; exit: x509write_crt_free(&m_crt); return hr; }
int main( int argc, char *argv[] ) { int ret = 0; x509_crt issuer_crt; pk_context loaded_issuer_key, loaded_subject_key; pk_context *issuer_key = &loaded_issuer_key, *subject_key = &loaded_subject_key; char buf[1024]; char issuer_name[128]; int i, j, n; char *p, *q, *r; #if defined(POLARSSL_X509_CSR_PARSE_C) char subject_name[128]; x509_csr csr; #endif x509write_cert crt; mpi serial; entropy_context entropy; ctr_drbg_context ctr_drbg; const char *pers = "crt example app"; /* * Set to sane values */ x509write_crt_init( &crt ); x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA1 ); pk_init( &loaded_issuer_key ); pk_init( &loaded_subject_key ); mpi_init( &serial ); #if defined(POLARSSL_X509_CSR_PARSE_C) x509_csr_init( &csr ); #endif x509_crt_init( &issuer_crt ); memset( buf, 0, 1024 ); if( argc == 0 ) { usage: printf( USAGE ); ret = 1; goto exit; } opt.issuer_crt = DFL_ISSUER_CRT; opt.request_file = DFL_REQUEST_FILE; opt.request_file = DFL_REQUEST_FILE; opt.subject_key = DFL_SUBJECT_KEY; opt.issuer_key = DFL_ISSUER_KEY; opt.subject_pwd = DFL_SUBJECT_PWD; opt.issuer_pwd = DFL_ISSUER_PWD; opt.output_file = DFL_OUTPUT_FILENAME; opt.subject_name = DFL_SUBJECT_NAME; opt.issuer_name = DFL_ISSUER_NAME; opt.not_before = DFL_NOT_BEFORE; opt.not_after = DFL_NOT_AFTER; opt.serial = DFL_SERIAL; opt.selfsign = DFL_SELFSIGN; opt.is_ca = DFL_IS_CA; opt.max_pathlen = DFL_MAX_PATHLEN; opt.key_usage = DFL_KEY_USAGE; opt.ns_cert_type = DFL_NS_CERT_TYPE; for( i = 1; i < argc; i++ ) { p = argv[i]; if( ( q = strchr( p, '=' ) ) == NULL ) goto usage; *q++ = '\0'; n = strlen( p ); for( j = 0; j < n; j++ ) { if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) argv[i][j] |= 0x20; } if( strcmp( p, "request_file" ) == 0 ) opt.request_file = q; else if( strcmp( p, "subject_key" ) == 0 ) opt.subject_key = q; else if( strcmp( p, "issuer_key" ) == 0 ) opt.issuer_key = q; else if( strcmp( p, "subject_pwd" ) == 0 ) opt.subject_pwd = q; else if( strcmp( p, "issuer_pwd" ) == 0 ) opt.issuer_pwd = q; else if( strcmp( p, "issuer_crt" ) == 0 ) opt.issuer_crt = q; else if( strcmp( p, "output_file" ) == 0 ) opt.output_file = q; else if( strcmp( p, "subject_name" ) == 0 ) { opt.subject_name = q; } else if( strcmp( p, "issuer_name" ) == 0 ) { opt.issuer_name = q; } else if( strcmp( p, "not_before" ) == 0 ) { opt.not_before = q; } else if( strcmp( p, "not_after" ) == 0 ) { opt.not_after = q; } else if( strcmp( p, "serial" ) == 0 ) { opt.serial = q; } else if( strcmp( p, "selfsign" ) == 0 ) { opt.selfsign = atoi( q ); if( opt.selfsign < 0 || opt.selfsign > 1 ) goto usage; } else if( strcmp( p, "is_ca" ) == 0 ) { opt.is_ca = atoi( q ); if( opt.is_ca < 0 || opt.is_ca > 1 ) goto usage; } else if( strcmp( p, "max_pathlen" ) == 0 ) { opt.max_pathlen = atoi( q ); if( opt.max_pathlen < -1 || opt.max_pathlen > 127 ) goto usage; } else if( strcmp( p, "key_usage" ) == 0 ) { while( q != NULL ) { if( ( r = strchr( q, ',' ) ) != NULL ) *r++ = '\0'; if( strcmp( q, "digital_signature" ) == 0 ) opt.key_usage |= KU_DIGITAL_SIGNATURE; else if( strcmp( q, "non_repudiation" ) == 0 ) opt.key_usage |= KU_NON_REPUDIATION; else if( strcmp( q, "key_encipherment" ) == 0 ) opt.key_usage |= KU_KEY_ENCIPHERMENT; else if( strcmp( q, "data_encipherment" ) == 0 ) opt.key_usage |= KU_DATA_ENCIPHERMENT; else if( strcmp( q, "key_agreement" ) == 0 ) opt.key_usage |= KU_KEY_AGREEMENT; else if( strcmp( q, "key_cert_sign" ) == 0 ) opt.key_usage |= KU_KEY_CERT_SIGN; else if( strcmp( q, "crl_sign" ) == 0 ) opt.key_usage |= KU_CRL_SIGN; else goto usage; q = r; } } else if( strcmp( p, "ns_cert_type" ) == 0 ) { while( q != NULL ) { if( ( r = strchr( q, ',' ) ) != NULL ) *r++ = '\0'; if( strcmp( q, "ssl_client" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_SSL_CLIENT; else if( strcmp( q, "ssl_server" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_SSL_SERVER; else if( strcmp( q, "email" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_EMAIL; else if( strcmp( q, "object_signing" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING; else if( strcmp( q, "ssl_ca" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_SSL_CA; else if( strcmp( q, "email_ca" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_EMAIL_CA; else if( strcmp( q, "object_signing_ca" ) == 0 ) opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING_CA; else goto usage; q = r; } } else goto usage; } printf("\n"); /* * 0. Seed the PRNG */ printf( " . Seeding the random number generator..." ); fflush( stdout ); entropy_init( &entropy ); if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, (const unsigned char *) pers, strlen( pers ) ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! ctr_drbg_init returned %d - %s\n", ret, buf ); goto exit; } printf( " ok\n" ); // Parse serial to MPI // printf( " . Reading serial number..." ); fflush( stdout ); if( ( ret = mpi_read_string( &serial, 10, opt.serial ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! mpi_read_string returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); // Parse issuer certificate if present // if( !opt.selfsign && strlen( opt.issuer_crt ) ) { /* * 1.0.a. Load the certificates */ printf( " . Loading the issuer certificate ..." ); fflush( stdout ); if( ( ret = x509_crt_parse_file( &issuer_crt, opt.issuer_crt ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509_crt_parse_file returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } ret = x509_dn_gets( issuer_name, sizeof(issuer_name), &issuer_crt.issuer ); if( ret < 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509_dn_gets returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } opt.issuer_name = issuer_name; printf( " ok\n" ); } #if defined(POLARSSL_X509_CSR_PARSE_C) // Parse certificate request if present // if( !opt.selfsign && strlen( opt.request_file ) ) { /* * 1.0.b. Load the CSR */ printf( " . Loading the certificate request ..." ); fflush( stdout ); if( ( ret = x509_csr_parse_file( &csr, opt.request_file ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509_csr_parse_file returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } ret = x509_dn_gets( subject_name, sizeof(subject_name), &csr.subject ); if( ret < 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509_dn_gets returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } opt.subject_name = subject_name; subject_key = &csr.pk; printf( " ok\n" ); } #endif /* POLARSSL_X509_CSR_PARSE_C */ /* * 1.1. Load the keys */ if( !opt.selfsign && !strlen( opt.request_file ) ) { printf( " . Loading the subject key ..." ); fflush( stdout ); ret = pk_parse_keyfile( &loaded_subject_key, opt.subject_key, opt.subject_pwd ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! pk_parse_keyfile returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); } printf( " . Loading the issuer key ..." ); fflush( stdout ); ret = pk_parse_keyfile( &loaded_issuer_key, opt.issuer_key, opt.issuer_pwd ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! pk_parse_keyfile returned -x%02x - %s\n\n", -ret, buf ); goto exit; } // Check if key and issuer certificate match // if( strlen( opt.issuer_crt ) ) { if( !pk_can_do( &issuer_crt.pk, POLARSSL_PK_RSA ) || mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->N, &pk_rsa( *issuer_key )->N ) != 0 || mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->E, &pk_rsa( *issuer_key )->E ) != 0 ) { printf( " failed\n ! issuer_key does not match issuer certificate\n\n" ); ret = -1; goto exit; } } printf( " ok\n" ); if( opt.selfsign ) { opt.subject_name = opt.issuer_name; subject_key = issuer_key; } x509write_crt_set_subject_key( &crt, subject_key ); x509write_crt_set_issuer_key( &crt, issuer_key ); /* * 1.0. Check the names for validity */ if( ( ret = x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_subject_name returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } if( ( ret = x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_issuer_name returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " . Setting certificate values ..." ); fflush( stdout ); ret = x509write_crt_set_serial( &crt, &serial ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_serial returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } ret = x509write_crt_set_validity( &crt, opt.not_before, opt.not_after ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_validity returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); printf( " . Adding the Basic Constraints extension ..." ); fflush( stdout ); ret = x509write_crt_set_basic_constraints( &crt, opt.is_ca, opt.max_pathlen ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_basic_contraints returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); #if defined(POLARSSL_SHA1_C) printf( " . Adding the Subject Key Identifier ..." ); fflush( stdout ); ret = x509write_crt_set_subject_key_identifier( &crt ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_subject_key_identifier returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); printf( " . Adding the Authority Key Identifier ..." ); fflush( stdout ); ret = x509write_crt_set_authority_key_identifier( &crt ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_authority_key_identifier returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); #endif /* POLARSSL_SHA1_C */ if( opt.key_usage ) { printf( " . Adding the Key Usage extension ..." ); fflush( stdout ); ret = x509write_crt_set_key_usage( &crt, opt.key_usage ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_key_usage returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); } if( opt.ns_cert_type ) { printf( " . Adding the NS Cert Type extension ..." ); fflush( stdout ); ret = x509write_crt_set_ns_cert_type( &crt, opt.ns_cert_type ); if( ret != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! x509write_crt_set_ns_cert_type returned -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); } /* * 1.2. Writing the request */ printf( " . Writing the certificate..." ); fflush( stdout ); if( ( ret = write_certificate( &crt, opt.output_file, ctr_drbg_random, &ctr_drbg ) ) != 0 ) { error_strerror( ret, buf, 1024 ); printf( " failed\n ! write_certifcate -0x%02x - %s\n\n", -ret, buf ); goto exit; } printf( " ok\n" ); exit: x509write_crt_free( &crt ); pk_free( &loaded_subject_key ); pk_free( &loaded_issuer_key ); mpi_free( &serial ); entropy_free( &entropy ); #if defined(_WIN32) printf( " + Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }