/*============================================================================ * CreateGuid *===========================================================================*/ OpcUa_Guid* OpcUa_Guid_Create(OpcUa_Guid* a_pGuid) { if(a_pGuid == OpcUa_Null) { return OpcUa_Null; } a_pGuid = OpcUa_P_Guid_Create(a_pGuid); return a_pGuid; }
/*============================================================================ * OpcUa_P_OpenSSL_X509_SelfSigned_Custom_Create *===========================================================================*/ OpcUa_StatusCode OpcUa_P_OpenSSL_X509_SelfSigned_Custom_Create( OpcUa_CryptoProvider* a_pProvider, OpcUa_Int32 a_serialNumber, OpcUa_UInt32 a_validToInSec, OpcUa_Crypto_NameEntry* a_pNameEntries, /* will be used for issuer and subject thus it's selfigned cert */ OpcUa_UInt a_nameEntriesCount, /* will be used for issuer and subject thus it's selfigned cert */ OpcUa_Key a_pSubjectPublicKey, /* EVP_PKEY* - type defines also public key algorithm */ OpcUa_Crypto_Extension* a_pExtensions, OpcUa_UInt a_extensionsCount, OpcUa_UInt a_signatureHashAlgorithm, /* EVP_sha1(),... */ OpcUa_Key a_pIssuerPrivateKey, /* EVP_PKEY* - type defines also signature algorithm */ OpcUa_ByteString* a_pCertificate) { OpcUa_UInt i; X509_NAME* pSubj = OpcUa_Null; X509V3_CTX ctx; const EVP_MD* pDigest = OpcUa_Null; X509* pCert = OpcUa_Null; EVP_PKEY* pSubjectPublicKey = OpcUa_Null; EVP_PKEY* pIssuerPrivateKey = OpcUa_Null; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_SelfSigned_Custom_Create"); OpcUa_ReferenceParameter(a_pProvider); OpcUa_ReturnErrorIfArgumentNull(a_pNameEntries); OpcUa_ReturnErrorIfArgumentNull(a_pExtensions); OpcUa_ReturnErrorIfArgumentNull(a_pIssuerPrivateKey.Key.Data); OpcUa_ReturnErrorIfArgumentNull(a_pCertificate); if(a_pSubjectPublicKey.Type != OpcUa_Crypto_KeyType_Rsa_Public) { uStatus = OpcUa_BadInvalidArgument; OpcUa_GotoErrorIfBad(uStatus); } if(a_pIssuerPrivateKey.Type != OpcUa_Crypto_KeyType_Rsa_Private) { uStatus = OpcUa_BadInvalidArgument; OpcUa_GotoErrorIfBad(uStatus); } pSubjectPublicKey = d2i_PublicKey(EVP_PKEY_RSA,OpcUa_Null,((const unsigned char**)&(a_pSubjectPublicKey.Key.Data)),a_pSubjectPublicKey.Key.Length); if(pSubjectPublicKey == OpcUa_Null) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } pIssuerPrivateKey = d2i_PrivateKey(EVP_PKEY_RSA,OpcUa_Null,((const unsigned char**)&(a_pIssuerPrivateKey.Key.Data)),a_pIssuerPrivateKey.Key.Length); if(pIssuerPrivateKey == OpcUa_Null) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* create new certificate object */ pCert = X509_new(); if(pCert == OpcUa_Null) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* set version of certificate (V3 since internal representation starts versioning from 0) */ if(X509_set_version(pCert, 2L) != 1) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* generate a unique number for a serial number if none provided. */ if(a_serialNumber == 0) { ASN1_INTEGER* pSerialNumber = X509_get_serialNumber(pCert); pSerialNumber->type = V_ASN1_INTEGER; pSerialNumber->data = OPENSSL_realloc(pSerialNumber->data, 16); pSerialNumber->length = 16; if(pSerialNumber->data == NULL || OpcUa_P_Guid_Create((OpcUa_Guid*)pSerialNumber->data) == NULL) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } } /* use the integer passed in - note the API should not be using a 32-bit integer - must fix sometime */ else if(ASN1_INTEGER_set(X509_get_serialNumber(pCert), a_serialNumber) == 0) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* add key to the request */ if(X509_set_pubkey(pCert, pSubjectPublicKey) != 1) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } if(pSubjectPublicKey != OpcUa_Null) { EVP_PKEY_free(pSubjectPublicKey); pSubjectPublicKey = OpcUa_Null; } /* assign the subject name */ pSubj = X509_NAME_new(); if(!pSubj) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* create and add entries to subject name */ for(i=0; i<a_nameEntriesCount; i++) { uStatus = OpcUa_P_OpenSSL_X509_Name_AddEntry(&pSubj, a_pNameEntries + i); OpcUa_GotoErrorIfBad(uStatus); } /* set subject name in request */ if(X509_set_subject_name(pCert, pSubj) != 1) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* set name of issuer (CA) */ if(X509_set_issuer_name(pCert, pSubj) != 1) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } if(!(X509_gmtime_adj(X509_get_notBefore(pCert), 0))) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* set ending time of the certificate */ if(!(X509_gmtime_adj(X509_get_notAfter(pCert), a_validToInSec))) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } /* add x509v3 extensions */ X509V3_set_ctx(&ctx, pCert, pCert, OpcUa_Null, OpcUa_Null, 0); for(i=0; i<a_extensionsCount; i++) { uStatus = OpcUa_P_OpenSSL_X509_AddCustomExtension(&pCert, a_pExtensions+i, &ctx); OpcUa_GotoErrorIfBad(uStatus); } /* sign certificate with the CA private key */ switch(a_signatureHashAlgorithm) { case OPCUA_P_SHA_160: pDigest = EVP_sha1(); break; case OPCUA_P_SHA_224: pDigest = EVP_sha224(); break; case OPCUA_P_SHA_256: pDigest = EVP_sha256(); break; case OPCUA_P_SHA_384: pDigest = EVP_sha384(); break; case OPCUA_P_SHA_512: pDigest = EVP_sha512(); break; default: uStatus = OpcUa_BadNotSupported; OpcUa_GotoErrorIfBad(uStatus); } if(!(X509_sign(pCert, pIssuerPrivateKey, pDigest))) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } if(X509_verify(pCert, pIssuerPrivateKey) <= 0) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } if(pIssuerPrivateKey != OpcUa_Null) { EVP_PKEY_free(pIssuerPrivateKey); pIssuerPrivateKey = OpcUa_Null; } if(pSubj != OpcUa_Null) { X509_NAME_free(pSubj); pSubj = OpcUa_Null; } /* prepare container */ memset(a_pCertificate, 0, sizeof(OpcUa_ByteString)); /* get required length for conversion target buffer */ a_pCertificate->Length = i2d_X509(pCert, NULL); if(a_pCertificate->Length <= 0) { /* conversion to DER not possible */ uStatus = OpcUa_Bad; } /* allocate conversion target buffer */ a_pCertificate->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertificate->Length); OpcUa_GotoErrorIfAllocFailed(a_pCertificate->Data); /* convert into DER */ a_pCertificate->Length = i2d_X509(pCert, &(a_pCertificate->Data)); if(a_pCertificate->Length <= 0) { /* conversion to DER not possible */ uStatus = OpcUa_Bad; } else { /* correct pointer incrementation by i2d_X509() */ a_pCertificate->Data -= a_pCertificate->Length; } X509_free(pCert); OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; X509_free(pCert); if(pSubjectPublicKey != OpcUa_Null) { EVP_PKEY_free(pSubjectPublicKey); } if(pIssuerPrivateKey != OpcUa_Null) { EVP_PKEY_free(pIssuerPrivateKey); } if(pSubj != OpcUa_Null) { X509_NAME_free(pSubj); } OpcUa_FinishErrorHandling; }