/* * ToDo: problems with RSA_PKCS1_OAEP_PADDING -> RSA_PKCS1_PSS_PADDING is * needed (Version 0.9.9); RSA_PKCS1_OAEP_PADDING is just for encryption */ OpcUa_StatusCode OpcUa_P_OpenSSL_RSA_Private_Sign( OpcUa_CryptoProvider* a_pProvider, OpcUa_ByteString a_data, OpcUa_Key* a_privateKey, OpcUa_Int16 a_padding, /* e.g. RSA_PKCS1_PADDING */ OpcUa_ByteString* a_pSignature) /* output length >= key length */ { EVP_PKEY* pSSLPrivateKey = OpcUa_Null; const unsigned char* pData = OpcUa_Null; int iErr = 0; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "RSA_Private_Sign"); /* unused parameters */ OpcUa_ReferenceParameter(a_pProvider); OpcUa_ReferenceParameter(a_padding); /* check parameters */ OpcUa_ReturnErrorIfArgumentNull(a_privateKey); OpcUa_ReturnErrorIfArgumentNull(a_pSignature); pData = a_privateKey->Key.Data; OpcUa_ReturnErrorIfArgumentNull(pData); OpcUa_ReturnErrorIfTrue((a_privateKey->Type != OpcUa_Crypto_KeyType_Rsa_Private), OpcUa_BadInvalidArgument); /* convert private key and check key length against buffer length */ pSSLPrivateKey = d2i_PrivateKey(EVP_PKEY_RSA, OpcUa_Null, &pData, a_privateKey->Key.Length); OpcUa_GotoErrorIfTrue((pSSLPrivateKey == OpcUa_Null), OpcUa_BadUnexpectedError); OpcUa_GotoErrorIfTrue((a_pSignature->Length < RSA_size(pSSLPrivateKey->pkey.rsa)), OpcUa_BadInvalidArgument); /* sign data */ iErr = RSA_sign(NID_sha1, a_data.Data, a_data.Length, a_pSignature->Data, (unsigned int*)&a_pSignature->Length, pSSLPrivateKey->pkey.rsa); OpcUa_GotoErrorIfTrue((iErr != 1), OpcUa_BadUnexpectedError); /* free internal key representation */ EVP_PKEY_free(pSSLPrivateKey); OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if(OpcUa_IsEqual(OpcUa_BadUnexpectedError)) { long lErr = ERR_get_error(); char* szErr = ERR_error_string(lErr, 0); if(szErr != OpcUa_Null) { OpcUa_P_Trace("*** RSA_Private_Sign: "); OpcUa_P_Trace(szErr); OpcUa_P_Trace(" ***\n"); } } if(pSSLPrivateKey != OpcUa_Null) { EVP_PKEY_free(pSSLPrivateKey); } OpcUa_FinishErrorHandling; }
/*============================================================================ * Get address information about the peer *===========================================================================*/ OpcUa_StatusCode OpcUa_P_RawSocket_GetPeerInfo( OpcUa_Socket a_RawSocket, OpcUa_CharA* a_achPeerInfoBuffer, OpcUa_UInt32 a_uiPeerInfoBufferSize) { int apiResult = 0; struct sockaddr_in sockAddrIn; size_t TempLen = sizeof(struct sockaddr_in); SOCKET winSocket = (SOCKET)OPCUA_P_SOCKET_INVALID; char* pchAddrBuf = OpcUa_Null; OpcUa_UInt16 usPort = 0; OpcUa_InitializeStatus(OpcUa_Module_Socket, "GetPeerInfo"); /* initial parameter check */ OpcUa_ReturnErrorIfTrue((a_RawSocket == (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID), OpcUa_BadInvalidArgument); OpcUa_ReturnErrorIfTrue((a_uiPeerInfoBufferSize < OPCUA_P_PEERINFO_MIN_SIZE), OpcUa_BadInvalidArgument); OpcUa_ReturnErrorIfArgumentNull(a_achPeerInfoBuffer); winSocket = (SOCKET)a_RawSocket; apiResult = getpeername(winSocket, (struct sockaddr*)&sockAddrIn, (int*)&TempLen); OpcUa_ReturnErrorIfTrue((apiResult != 0), OpcUa_BadInternalError); /* IP */ pchAddrBuf = inet_ntoa(sockAddrIn.sin_addr); OpcUa_GotoErrorIfTrue(pchAddrBuf == OpcUa_Null, OpcUa_BadInternalError); /* Port */ usPort = OpcUa_P_RawSocket_NToHS((OpcUa_UInt16)sockAddrIn.sin_port); /* build result string */ TempLen = strlen(pchAddrBuf); #if OPCUA_USE_SAFE_FUNCTIONS OpcUa_GotoErrorIfTrue((strncpy_s(a_achPeerInfoBuffer, a_uiPeerInfoBufferSize + 1, pchAddrBuf, TempLen) != 0), OpcUa_Bad); a_achPeerInfoBuffer[TempLen] = ':'; TempLen++; sprintf_s(&a_achPeerInfoBuffer[TempLen], a_uiPeerInfoBufferSize - TempLen, "%u", usPort); #else /* OPCUA_USE_SAFE_FUNCTIONS */ OpcUa_GotoErrorIfTrue((strncpy(a_achPeerInfoBuffer, pchAddrBuf, TempLen) != a_achPeerInfoBuffer), OpcUa_Bad); a_achPeerInfoBuffer[TempLen] = ':'; sprintf(&a_achPeerInfoBuffer[TempLen + 1], "%u", usPort); #endif /* OPCUA_USE_SAFE_FUNCTIONS */ OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; OpcUa_FinishErrorHandling; }
/*============================================================================ * OpcUa_EnumeratedType_FindValue *===========================================================================*/ OPCUA_EXPORT OpcUa_StatusCode OpcUa_EnumeratedType_FindValue( OpcUa_EnumeratedType* a_pType, OpcUa_StringA a_sName, OpcUa_Int32* a_pValue) { OpcUa_UInt32 ii = 0; OpcUa_InitializeStatus(OpcUa_Module_Serializer, "EnumeratedType_FindValue"); OpcUa_ReturnErrorIfArgumentNull(a_pType); OpcUa_ReturnErrorIfArgumentNull(a_sName); OpcUa_ReturnErrorIfArgumentNull(a_pValue); *a_pValue = 0; for (ii = 0; a_pType->Values[ii].Name != OpcUa_Null; ii++) { if (OpcUa_StrCmpA(a_pType->Values[ii].Name, a_sName) == 0) { *a_pValue = a_pType->Values[ii].Value; break; } } OpcUa_GotoErrorIfTrue(a_pType->Values[ii].Name == OpcUa_Null, OpcUa_BadInvalidArgument); OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; /* nothing to do */ OpcUa_FinishErrorHandling; }
/*============================================================================ * OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile *===========================================================================*/ OpcUa_StatusCode OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile( OpcUa_StringA a_privateKeyFile, OpcUa_P_FileFormat a_fileFormat, OpcUa_StringA a_password, /* optional: just needed encrypted PEM */ OpcUa_ByteString* a_pPrivateKey) { BIO* pPrivateKeyFile = OpcUa_Null; RSA* pRsaPrivateKey = OpcUa_Null; EVP_PKEY* pEvpKey = OpcUa_Null; unsigned char* pData; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "RSA_LoadPrivateKeyFromFile"); /* check parameters */ OpcUa_ReturnErrorIfArgumentNull(a_privateKeyFile); OpcUa_ReturnErrorIfArgumentNull(a_pPrivateKey); if(a_fileFormat == OpcUa_Crypto_Encoding_Invalid) { return OpcUa_BadInvalidArgument; } OpcUa_ReferenceParameter(a_password); /* open file */ pPrivateKeyFile = BIO_new_file((const char*)a_privateKeyFile, "rb"); OpcUa_ReturnErrorIfArgumentNull(pPrivateKeyFile); /* read and convert file */ switch(a_fileFormat) { case OpcUa_Crypto_Encoding_PEM: { /* read from file */ pEvpKey = PEM_read_bio_PrivateKey( pPrivateKeyFile, /* file */ NULL, /* key struct */ 0, /* password callback */ a_password); /* default passphrase or arbitrary handle */ OpcUa_GotoErrorIfNull(pEvpKey, OpcUa_Bad); break; } case OpcUa_Crypto_Encoding_PKCS12: { int iResult = 0; /* read from file. */ PKCS12* pPkcs12 = d2i_PKCS12_bio(pPrivateKeyFile, NULL); if (pPkcs12 == 0) { OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError); } /* parse the certificate. */ iResult = PKCS12_parse(pPkcs12, a_password, &pEvpKey, NULL, NULL); if (iResult == 0) { OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError); } /* free certificate. */ PKCS12_free(pPkcs12); pPkcs12 = NULL; break; } case OpcUa_Crypto_Encoding_DER: default: { uStatus = OpcUa_BadNotSupported; OpcUa_GotoError; } } /* convert to intermediary openssl struct */ pRsaPrivateKey = EVP_PKEY_get1_RSA(pEvpKey); EVP_PKEY_free(pEvpKey); OpcUa_GotoErrorIfNull(pRsaPrivateKey, OpcUa_Bad); /* get required length */ a_pPrivateKey->Length = i2d_RSAPrivateKey(pRsaPrivateKey, OpcUa_Null); OpcUa_GotoErrorIfTrue((a_pPrivateKey->Length <= 0), OpcUa_Bad); /* allocate target buffer */ a_pPrivateKey->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pPrivateKey->Length); OpcUa_GotoErrorIfAllocFailed(a_pPrivateKey->Data); /* do real conversion */ pData = a_pPrivateKey->Data; a_pPrivateKey->Length = i2d_RSAPrivateKey(pRsaPrivateKey, &pData); OpcUa_GotoErrorIfTrue((a_pPrivateKey->Length <= 0), OpcUa_Bad); RSA_free(pRsaPrivateKey); BIO_free(pPrivateKeyFile); OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if(pEvpKey) { EVP_PKEY_free(pEvpKey); } if(a_pPrivateKey != OpcUa_Null) { if(a_pPrivateKey->Data != OpcUa_Null) { OpcUa_P_Memory_Free(a_pPrivateKey->Data); a_pPrivateKey->Data = OpcUa_Null; a_pPrivateKey->Length = -1; } } if(pPrivateKeyFile != NULL) { BIO_free(pPrivateKeyFile); } if(pRsaPrivateKey != NULL) { RSA_free(pRsaPrivateKey); } OpcUa_FinishErrorHandling; }
/* ToDo: Create Access to OpenSSL certificate store => Only API to In-Memory-Store is available for version 0.9.8x => Wait until Directory- and/or File-Store is available */ OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_LoadCertificate( OpcUa_PKIProvider* a_pProvider, OpcUa_Void* a_pLoadHandle, OpcUa_Void* a_pCertificateStore, OpcUa_ByteString* a_pCertificate) { OpcUa_Byte* buf = OpcUa_Null; OpcUa_Byte* p = OpcUa_Null; FILE* pCertificateFile = OpcUa_Null; X509* pTmpCert = OpcUa_Null; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_LoadCertificate"); OpcUa_ReturnErrorIfArgumentNull(a_pProvider); OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle); OpcUa_ReturnErrorIfArgumentNull(a_pLoadHandle); OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore); OpcUa_ReturnErrorIfArgumentNull(a_pCertificate); /* read DER certificates */ pCertificateFile = fopen((const char*)a_pLoadHandle, "r"); /* check for valid file handle */ OpcUa_GotoErrorIfTrue((pCertificateFile == OpcUa_Null), OpcUa_BadInvalidArgument); if(!(pTmpCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null))) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } a_pCertificate->Length = i2d_X509(pTmpCert, NULL); buf = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertificate->Length); OpcUa_GotoErrorIfAllocFailed(buf); p = buf; for (;;) { i2d_X509(pTmpCert, &p); X509_free(pTmpCert); if(!(pTmpCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null))) { break; } p = OpcUa_P_Memory_ReAlloc(buf, a_pCertificate->Length + i2d_X509(pTmpCert, NULL)); OpcUa_GotoErrorIfAllocFailed(p); buf = p; p = buf + a_pCertificate->Length; a_pCertificate->Length += i2d_X509(pTmpCert, NULL); } if(fclose(pCertificateFile) != 0) { pCertificateFile = OpcUa_Null; uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } a_pCertificate->Data = buf; OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if(pCertificateFile != OpcUa_Null) { fclose(pCertificateFile); } if(pTmpCert != OpcUa_Null) { X509_free(pTmpCert); } if(buf != OpcUa_Null) { OpcUa_P_Memory_Free(buf); } OpcUa_FinishErrorHandling; }
/* ToDo: Create Access to OpenSSL certificate store => Only API to In-Memory-Store is available for version 0.9.8x => Wait until Directory- and/or File-Store is available */ OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_SaveCertificate( OpcUa_PKIProvider* a_pProvider, OpcUa_ByteString* a_pCertificate, OpcUa_Void* a_pCertificateStore, OpcUa_Void* a_pSaveHandle) /* Index or number within store/destination filepath */ { X509* pX509Certificate = OpcUa_Null; FILE* pCertificateFile = OpcUa_Null; const unsigned char* p; OpcUa_UInt32 i; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_SaveCertificate"); OpcUa_ReturnErrorIfArgumentNull(a_pProvider); OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle); OpcUa_ReturnErrorIfArgumentNull(a_pCertificate); OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore); OpcUa_ReturnErrorIfArgumentNull(a_pSaveHandle); /* save DER certificate */ pCertificateFile = fopen((const char*)a_pSaveHandle, "w"); /* check for valid file handle */ OpcUa_GotoErrorIfTrue((pCertificateFile == OpcUa_Null), OpcUa_BadInvalidArgument); /* convert openssl X509 certificate to DER encoded bytestring certificate */ p = a_pCertificate->Data; while (p < a_pCertificate->Data + a_pCertificate->Length) { if(!(pX509Certificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Data + a_pCertificate->Length - p))) { fclose(pCertificateFile); uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } i = i2d_X509_fp(pCertificateFile, pX509Certificate); if(i < 1) { fclose(pCertificateFile); uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } X509_free(pX509Certificate); pX509Certificate = OpcUa_Null; } if(fclose(pCertificateFile) != 0) { uStatus = OpcUa_Bad; OpcUa_GotoErrorIfBad(uStatus); } OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if (pX509Certificate != OpcUa_Null) { X509_free(pX509Certificate); } OpcUa_FinishErrorHandling; }
/*============================================================================ * Create a client socket *===========================================================================*/ OpcUa_StatusCode OPCUA_DLLCALL OpcUa_P_SocketManager_CreateClient( OpcUa_SocketManager a_hSocketManager, OpcUa_StringA a_sRemoteAddress, OpcUa_UInt16 a_uLocalPort, OpcUa_Socket_EventCallback a_pfnSocketCallBack, OpcUa_Void* a_pCallbackData, OpcUa_Socket* a_pSocket) { OpcUa_InternalSocket* pNewClientSocket = OpcUa_Null; OpcUa_InternalSocketManager* pInternalSocketManager = OpcUa_Null; OpcUa_UInt16 uPort = 0; OpcUa_StringA sRemoteAdress = OpcUa_Null; OpcUa_InitializeStatus(OpcUa_Module_Socket, "CreateClient"); #if !OPCUA_MULTITHREADED if(a_hSocketManager == OpcUa_Null) { a_hSocketManager = OpcUa_Socket_g_SocketManager; } #endif OpcUa_ReturnErrorIfArgumentNull(a_hSocketManager); OpcUa_ReturnErrorIfArgumentNull(a_pSocket); OpcUa_ReturnErrorIfArgumentNull(a_sRemoteAddress); /* parse address */ uStatus = OpcUa_P_ParseUrl( a_sRemoteAddress, &sRemoteAdress, &uPort); OpcUa_ReturnErrorIfBad(uStatus); pInternalSocketManager = (OpcUa_InternalSocketManager*)a_hSocketManager; pNewClientSocket = (OpcUa_InternalSocket*)OpcUa_SocketManager_FindFreeSocket( (OpcUa_SocketManager)pInternalSocketManager, OpcUa_False); if (pNewClientSocket == OpcUa_Null) { OpcUa_P_Memory_Free(sRemoteAdress); uStatus = OpcUa_BadMaxConnectionsReached; /* no socket left in the list. */ goto Error; } /* Create client socket. */ pNewClientSocket->rawSocket = OpcUa_P_Socket_CreateClient( a_uLocalPort, uPort, sRemoteAdress, &uStatus); OpcUa_P_Memory_Free(sRemoteAdress); OpcUa_GotoErrorIfTrue( pNewClientSocket->rawSocket == (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID, OpcUa_BadCommunicationError); pNewClientSocket->pfnEventCallback = a_pfnSocketCallBack; pNewClientSocket->pvUserData = a_pCallbackData; pNewClientSocket->Flags.bOwnThread = OpcUa_False; pNewClientSocket->Flags.EventMask = OPCUA_SOCKET_READ_EVENT | OPCUA_SOCKET_EXCEPT_EVENT | OPCUA_SOCKET_CONNECT_EVENT | OPCUA_SOCKET_TIMEOUT_EVENT; OPCUA_SOCKET_SETVALID(pNewClientSocket); /* return the new client socket */ *a_pSocket = pNewClientSocket; /* break loop to add new socket into eventing */ uStatus = OpcUa_P_SocketManager_InterruptLoop( a_hSocketManager, OPCUA_SOCKET_RENEWLOOP_EVENT, OpcUa_False); OpcUa_GotoErrorIfBad(uStatus); OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if(pNewClientSocket != OpcUa_Null) { if(pNewClientSocket->rawSocket != (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID) { OpcUa_P_RawSocket_Close(pNewClientSocket->rawSocket); pNewClientSocket->rawSocket = (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID; } OPCUA_SOCKET_INVALIDATE(pNewClientSocket); } OpcUa_FinishErrorHandling; }
/*============================================================================ * OpcUa_P_OpenSSL_X509_GetPrivateKey *===========================================================================*/ OpcUa_StatusCode OpcUa_P_OpenSSL_X509_GetPrivateKey( OpcUa_CryptoProvider* a_pProvider, OpcUa_StringA a_certificateFileName, OpcUa_StringA a_password, /* this is optional */ OpcUa_Key* a_pPrivateKey) { BIO* pCertFile = OpcUa_Null; PKCS12* pPKCS12Cert = OpcUa_Null; EVP_PKEY* pPrivateKey = OpcUa_Null; RSA* pRsaPrivateKey = OpcUa_Null; OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_GetPrivateKey"); OpcUa_ReferenceParameter(a_pProvider); OpcUa_ReturnErrorIfArgumentNull(a_pProvider); OpcUa_ReturnErrorIfArgumentNull(a_certificateFileName); OpcUa_ReturnErrorIfArgumentNull(a_pPrivateKey); /* import certificate from file by the given encoding type */ pCertFile = BIO_new_file((const char*)a_certificateFileName, "r"); OpcUa_ReturnErrorIfArgumentNull(pCertFile); /* convert certificate file handle to PKCS12 structure */ d2i_PKCS12_bio(pCertFile, &pPKCS12Cert); /* close certificat file handle */ BIO_free(pCertFile); if(pPKCS12Cert != OpcUa_Null) { /* get the private key from the PKCS12 structure*/ PKCS12_parse(pPKCS12Cert, a_password, &pPrivateKey, OpcUa_Null, OpcUa_Null); } else { uStatus = OpcUa_Bad; OpcUa_ReturnStatusCode; } if(pPKCS12Cert != OpcUa_Null) { PKCS12_free(pPKCS12Cert); pPKCS12Cert = OpcUa_Null; } switch(EVP_PKEY_type(pPrivateKey->type)) { case EVP_PKEY_RSA: { /* convert to intermediary openssl struct */ pRsaPrivateKey = EVP_PKEY_get1_RSA(pPrivateKey); EVP_PKEY_free(pPrivateKey); OpcUa_GotoErrorIfNull(pRsaPrivateKey, OpcUa_Bad); /* get required length */ a_pPrivateKey->Key.Length = i2d_RSAPrivateKey(pRsaPrivateKey, OpcUa_Null); OpcUa_GotoErrorIfTrue(a_pPrivateKey->Key.Length <= 0, OpcUa_Bad); if(a_pPrivateKey->Key.Data == OpcUa_Null) { OpcUa_ReturnStatusCode; } /* do real conversion */ a_pPrivateKey->Key.Length = i2d_RSAPrivateKey( pRsaPrivateKey, &a_pPrivateKey->Key.Data); OpcUa_GotoErrorIfTrue(a_pPrivateKey->Key.Length <= 0, OpcUa_Bad); if(pRsaPrivateKey != OpcUa_Null) { RSA_free(pRsaPrivateKey); pRsaPrivateKey = OpcUa_Null; } /* correct buffer pointer */ a_pPrivateKey->Key.Data -= a_pPrivateKey->Key.Length; a_pPrivateKey->Type = OpcUa_Crypto_KeyType_Rsa_Private; break; } case EVP_PKEY_EC: case EVP_PKEY_DSA: case EVP_PKEY_DH: default: { uStatus = OpcUa_BadNotSupported; OpcUa_GotoErrorIfBad(uStatus); } } OpcUa_ReturnStatusCode; OpcUa_BeginErrorHandling; if(pRsaPrivateKey != OpcUa_Null) { RSA_free(pRsaPrivateKey); } if(pPrivateKey != OpcUa_Null) { EVP_PKEY_free(pPrivateKey); } OpcUa_FinishErrorHandling; }