2 ** NetXMS - Network Management System
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <nms_threads.h>
36 #ifdef _WITH_ENCRYPTION
37 #include <openssl/ssl.h>
41 * Temporary buffer structure for RecvNXCPMessage() function
47 char buffer
[NXCP_TEMP_BUF_SIZE
];
58 class LIBNETXMS_EXPORTABLE NXCPMessage
64 MessageField
*m_fields
; // Message fields
65 int m_version
; // Protocol version
66 BYTE
*m_data
; // binary data
67 size_t m_dataSize
; // binary data size
69 void *set(UINT32 fieldId
, BYTE type
, const void *value
, bool isSigned
= false, size_t size
= 0);
70 void *get(UINT32 fieldId
, BYTE requiredType
, BYTE
*fieldType
= NULL
) const;
71 NXCP_MESSAGE_FIELD
*find(UINT32 fieldId
) const;
74 NXCPMessage(int version
= NXCP_VERSION
);
75 NXCPMessage(UINT16 code
, UINT32 id
, int version
= NXCP_VERSION
);
76 NXCPMessage(NXCPMessage
*msg
);
77 NXCPMessage(NXCP_MESSAGE
*rawMag
, int version
= NXCP_VERSION
);
80 NXCP_MESSAGE
*createMessage(bool allowCompression
= false) const;
82 UINT16
getCode() const { return m_code
; }
83 void setCode(UINT16 code
) { m_code
= code
; }
85 UINT32
getId() const { return m_id
; }
86 void setId(UINT32 id
) { m_id
= id
; }
88 int getProtocolVersion() const { return m_version
; }
89 void setProtocolVersion(int version
) { m_version
= version
; }
91 bool isEndOfFile() const { return (m_flags
& MF_END_OF_FILE
) ?
true : false; }
92 bool isEndOfSequence() const { return (m_flags
& MF_END_OF_SEQUENCE
) ?
true : false; }
93 bool isReverseOrder() const { return (m_flags
& MF_REVERSE_ORDER
) ?
true : false; }
94 bool isBinary() const { return (m_flags
& MF_BINARY
) ?
true : false; }
95 bool isControl() const { return (m_flags
& MF_CONTROL
) ?
true : false; }
96 bool isCompressedStream() const { return ((m_flags
& (MF_COMPRESSED
| MF_STREAM
)) == (MF_COMPRESSED
| MF_STREAM
)) ?
true : false; }
98 const BYTE
*getBinaryData() const { return m_data
; }
99 size_t getBinaryDataSize() const { return m_dataSize
; }
101 bool isFieldExist(UINT32 fieldId
) const { return find(fieldId
) != NULL
; }
102 int getFieldType(UINT32 fieldId
) const;
104 void setField(UINT32 fieldId
, INT16 value
) { set(fieldId
, NXCP_DT_INT16
, &value
, true); }
105 void setField(UINT32 fieldId
, UINT16 value
) { set(fieldId
, NXCP_DT_INT16
, &value
, false); }
106 void setField(UINT32 fieldId
, INT32 value
) { set(fieldId
, NXCP_DT_INT32
, &value
, true); }
107 void setField(UINT32 fieldId
, UINT32 value
) { set(fieldId
, NXCP_DT_INT32
, &value
, false); }
108 void setField(UINT32 fieldId
, INT64 value
) { set(fieldId
, NXCP_DT_INT64
, &value
, true); }
109 void setField(UINT32 fieldId
, UINT64 value
) { set(fieldId
, NXCP_DT_INT64
, &value
, false); }
110 void setField(UINT32 fieldId
, double value
) { set(fieldId
, NXCP_DT_FLOAT
, &value
); }
111 void setField(UINT32 fieldId
, bool value
) { INT16 v
= value ?
1 : 0; set(fieldId
, NXCP_DT_INT16
, &v
, true); }
112 void setField(UINT32 fieldId
, const TCHAR
*value
) { if (value
!= NULL
) set(fieldId
, NXCP_DT_STRING
, value
); }
113 void setField(UINT32 fieldId
, const TCHAR
*value
, size_t maxLen
) { if (value
!= NULL
) set(fieldId
, NXCP_DT_STRING
, value
, false, maxLen
); }
114 void setField(UINT32 fieldId
, const BYTE
*value
, size_t size
) { set(fieldId
, NXCP_DT_BINARY
, value
, false, size
); }
115 void setField(UINT32 fieldId
, const InetAddress
& value
) { set(fieldId
, NXCP_DT_INETADDR
, &value
); }
116 void setField(UINT32 fieldId
, const uuid
& value
) { set(fieldId
, NXCP_DT_BINARY
, value
.getValue(), false, UUID_LENGTH
); }
117 void setField(UINT32 fieldId
, const MacAddress
& value
) { set(fieldId
, NXCP_DT_BINARY
, value
.value(), false, value
.length()); }
119 void setFieldFromMBString(UINT32 fieldId
, const char *value
);
121 void setFieldFromMBString(UINT32 fieldId
, const char *value
) { set(fieldId
, NXCP_DT_STRING
, value
); }
123 void setFieldFromTime(UINT32 fieldId
, time_t value
) { UINT64 t
= (UINT64
)value
; set(fieldId
, NXCP_DT_INT64
, &t
); }
124 void setFieldFromInt32Array(UINT32 fieldId
, size_t numElements
, const UINT32
*elements
);
125 void setFieldFromInt32Array(UINT32 fieldId
, const IntegerArray
<UINT32
> *data
);
126 bool setFieldFromFile(UINT32 fieldId
, const TCHAR
*pszFileName
);
128 INT16
getFieldAsInt16(UINT32 fieldId
) const;
129 UINT16
getFieldAsUInt16(UINT32 fieldId
) const;
130 INT32
getFieldAsInt32(UINT32 fieldId
) const;
131 UINT32
getFieldAsUInt32(UINT32 fieldId
) const;
132 INT64
getFieldAsInt64(UINT32 fieldId
) const;
133 UINT64
getFieldAsUInt64(UINT32 fieldId
) const;
134 double getFieldAsDouble(UINT32 fieldId
) const;
135 bool getFieldAsBoolean(UINT32 fieldId
) const;
136 time_t getFieldAsTime(UINT32 fieldId
) const;
137 UINT32
getFieldAsInt32Array(UINT32 fieldId
, UINT32 numElements
, UINT32
*buffer
) const;
138 UINT32
getFieldAsInt32Array(UINT32 fieldId
, IntegerArray
<UINT32
> *data
) const;
139 const BYTE
*getBinaryFieldPtr(UINT32 fieldId
, size_t *size
) const;
140 TCHAR
*getFieldAsString(UINT32 fieldId
, TCHAR
*buffer
= NULL
, size_t bufferSize
= 0) const;
141 char *getFieldAsMBString(UINT32 fieldId
, char *buffer
= NULL
, size_t bufferSize
= 0) const;
142 char *getFieldAsUtf8String(UINT32 fieldId
, char *buffer
= NULL
, size_t bufferSize
= 0) const;
143 UINT32
getFieldAsBinary(UINT32 fieldId
, BYTE
*buffer
, size_t bufferSize
) const;
144 InetAddress
getFieldAsInetAddress(UINT32 fieldId
) const;
145 MacAddress
getFieldAsMacAddress(UINT32 fieldId
) const;
146 uuid
getFieldAsGUID(UINT32 fieldId
) const;
148 void deleteAllFields();
150 void disableEncryption() { m_flags
|= MF_DONT_ENCRYPT
; }
151 void setEndOfSequence() { m_flags
|= MF_END_OF_SEQUENCE
; }
152 void setReverseOrderFlag() { m_flags
|= MF_REVERSE_ORDER
; }
154 static String
dump(const NXCP_MESSAGE
*msg
, int version
);
158 * Message waiting queue element structure
162 void *msg
; // Pointer to message, either to NXCPMessage object or raw message
163 UINT64 sequence
; // Sequence number
164 UINT32 id
; // Message ID
165 UINT32 ttl
; // Message time-to-live in milliseconds
166 UINT16 code
; // Message code
167 UINT16 isBinary
; // 1 for binary (raw) messages
168 } WAIT_QUEUE_ELEMENT
;
171 * Max number of waiting threads in message queue
173 #define MAX_MSGQUEUE_WAITERS 32
176 * Message waiting queue class
178 class LIBNETXMS_EXPORTABLE MsgWaitQueue
182 CRITICAL_SECTION m_mutex
;
183 HANDLE m_wakeupEvents
[MAX_MSGQUEUE_WAITERS
];
184 BYTE m_waiters
[MAX_MSGQUEUE_WAITERS
];
185 #elif defined(_USE_GNU_PTH)
187 pth_cond_t m_wakeupCondition
;
189 pthread_mutex_t m_mutex
;
190 pthread_cond_t m_wakeupCondition
;
195 WAIT_QUEUE_ELEMENT
*m_elements
;
198 void *waitForMessageInternal(UINT16 isBinary
, UINT16 code
, UINT32 id
, UINT32 timeout
);
203 EnterCriticalSection(&m_mutex
);
204 #elif defined(_USE_GNU_PTH)
205 pth_mutex_acquire(&m_mutex
, FALSE
, NULL
);
207 pthread_mutex_lock(&m_mutex
);
214 LeaveCriticalSection(&m_mutex
);
215 #elif defined(_USE_GNU_PTH)
216 pth_mutex_release(&m_mutex
);
218 pthread_mutex_unlock(&m_mutex
);
222 void housekeeperRun();
224 static Mutex m_housekeeperLock
;
225 static HashMap
<UINT64
, MsgWaitQueue
> *m_activeQueues
;
226 static Condition m_shutdownCondition
;
227 static THREAD m_housekeeperThread
;
228 static EnumerationCallbackResult
houseKeeperCallback(const void *key
, const void *object
, void *arg
);
229 static THREAD_RESULT THREAD_CALL
housekeeperThread(void *);
230 static EnumerationCallbackResult
diagInfoCallback(const void *key
, const void *object
, void *arg
);
236 void put(NXCPMessage
*pMsg
);
237 void put(NXCP_MESSAGE
*pMsg
);
238 NXCPMessage
*waitForMessage(WORD wCode
, UINT32 dwId
, UINT32 dwTimeOut
)
240 return (NXCPMessage
*)waitForMessageInternal(0, wCode
, dwId
, dwTimeOut
);
242 NXCP_MESSAGE
*waitForRawMessage(WORD wCode
, UINT32 dwId
, UINT32 dwTimeOut
)
244 return (NXCP_MESSAGE
*)waitForMessageInternal(1, wCode
, dwId
, dwTimeOut
);
248 void setHoldTime(UINT32 holdTime
) { m_holdTime
= holdTime
; }
250 static void shutdown();
251 static String
getDiagInfo();
255 * NXCP encryption context
257 class LIBNETXMS_EXPORTABLE NXCPEncryptionContext
: public RefCountObject
263 BYTE m_iv
[EVP_MAX_IV_LENGTH
];
264 #ifdef _WITH_ENCRYPTION
265 MUTEX m_encryptorLock
;
267 EVP_CIPHER_CTX
*m_encryptor
;
268 EVP_CIPHER_CTX
*m_decryptor
;
269 #elif WITH_COMMONCRYPTO
270 CCCryptorRef m_encryptor
;
271 CCCryptorRef m_decryptor
;
275 NXCPEncryptionContext();
276 bool initCipher(int cipher
);
279 static NXCPEncryptionContext
*create(NXCPMessage
*msg
, RSA
*privateKey
);
280 static NXCPEncryptionContext
*create(UINT32 ciphers
);
282 virtual ~NXCPEncryptionContext();
284 NXCP_ENCRYPTED_MESSAGE
*encryptMessage(NXCP_MESSAGE
*msg
);
285 bool decryptMessage(NXCP_ENCRYPTED_MESSAGE
*msg
, BYTE
*decryptionBuffer
);
287 int getCipher() { return m_cipher
; }
288 BYTE
*getSessionKey() { return m_sessionKey
; }
289 int getKeyLength() { return m_keyLength
; }
290 BYTE
*getIV() { return m_iv
; }
294 * Message receiver result codes
296 enum MessageReceiverResult
301 MSGRECV_COMM_FAILURE
= 3,
302 MSGRECV_DECRYPTION_FAILURE
= 4,
303 MSGRECV_PROTOCOL_ERROR
= 5
307 * Message receiver - abstract base class
309 class LIBNETXMS_EXPORTABLE AbstractMessageReceiver
313 BYTE
*m_decryptionBuffer
;
314 NXCPEncryptionContext
*m_encryptionContext
;
315 size_t m_initialSize
;
319 size_t m_bytesToSkip
;
321 NXCPMessage
*getMessageFromBuffer(bool *protocolError
);
324 virtual int readBytes(BYTE
*buffer
, size_t size
, UINT32 timeout
) = 0;
327 AbstractMessageReceiver(size_t initialSize
, size_t maxSize
);
328 virtual ~AbstractMessageReceiver();
330 void setEncryptionContext(NXCPEncryptionContext
*ctx
) { m_encryptionContext
= ctx
; }
332 NXCPMessage
*readMessage(UINT32 timeout
, MessageReceiverResult
*result
);
333 NXCP_MESSAGE
*getRawMessageBuffer() { return (NXCP_MESSAGE
*)m_buffer
; }
335 static const TCHAR
*resultToText(MessageReceiverResult result
);
339 * Message receiver - socket implementation
341 class LIBNETXMS_EXPORTABLE SocketMessageReceiver
: public AbstractMessageReceiver
347 virtual int readBytes(BYTE
*buffer
, size_t size
, UINT32 timeout
);
350 SocketMessageReceiver(SOCKET socket
, size_t initialSize
, size_t maxSize
);
351 virtual ~SocketMessageReceiver();
355 * Message receiver - comm channel implementation
357 class LIBNETXMS_EXPORTABLE CommChannelMessageReceiver
: public AbstractMessageReceiver
360 AbstractCommChannel
*m_channel
;
363 virtual int readBytes(BYTE
*buffer
, size_t size
, UINT32 timeout
);
366 CommChannelMessageReceiver(AbstractCommChannel
*channel
, size_t initialSize
, size_t maxSize
);
367 virtual ~CommChannelMessageReceiver();
370 #ifdef _WITH_ENCRYPTION
373 * Message receiver - SSL/TLS implementation
375 class LIBNETXMS_EXPORTABLE TlsMessageReceiver
: public AbstractMessageReceiver
383 virtual int readBytes(BYTE
*buffer
, size_t size
, UINT32 timeout
);
386 TlsMessageReceiver(SOCKET socket
, SSL
*ssl
, MUTEX mutex
, size_t initialSize
, size_t maxSize
);
387 virtual ~TlsMessageReceiver();
390 #endif /* _WITH_ENCRYPTION */
393 * Message receiver - UNIX socket/named pipe implementation
395 class LIBNETXMS_EXPORTABLE PipeMessageReceiver
: public AbstractMessageReceiver
404 virtual int readBytes(BYTE
*buffer
, size_t size
, UINT32 timeout
);
407 PipeMessageReceiver(HPIPE pipe
, size_t initialSize
, size_t maxSize
);
408 virtual ~PipeMessageReceiver();
412 * NXCP stresam compression methods
414 enum NXCPStreamCompressionMethod
416 NXCP_STREAM_COMPRESSION_NONE
= 0,
417 NXCP_STREAM_COMPRESSION_LZ4
= 1,
418 NXCP_STREAM_COMPRESSION_DEFLATE
= 2
422 * Abstract stream compressor
424 class LIBNETXMS_EXPORTABLE StreamCompressor
427 virtual ~StreamCompressor();
429 virtual size_t compress(const BYTE
*in
, size_t inSize
, BYTE
*out
, size_t maxOutSize
) = 0;
430 virtual size_t decompress(const BYTE
*in
, size_t inSize
, const BYTE
**out
) = 0;
431 virtual size_t compressBufferSize(size_t dataSize
) = 0;
433 static StreamCompressor
*create(NXCPStreamCompressionMethod method
, bool compress
, size_t maxBlockSize
);
437 * Dummy stream compressor
439 class LIBNETXMS_EXPORTABLE DummyStreamCompressor
: public StreamCompressor
442 virtual ~DummyStreamCompressor();
444 virtual size_t compress(const BYTE
*in
, size_t inSize
, BYTE
*out
, size_t maxOutSize
);
445 virtual size_t decompress(const BYTE
*in
, size_t inSize
, const BYTE
**out
);
446 virtual size_t compressBufferSize(size_t dataSize
);
449 struct __LZ4_stream_t
;
450 struct __LZ4_streamDecode_t
;
453 * LZ4 stream compressor
455 class LIBNETXMS_EXPORTABLE LZ4StreamCompressor
: public StreamCompressor
460 __LZ4_stream_t
*encoder
;
461 __LZ4_streamDecode_t
*decoder
;
464 size_t m_maxBlockSize
;
470 LZ4StreamCompressor(bool compress
, size_t maxBlockSize
);
471 virtual ~LZ4StreamCompressor();
473 virtual size_t compress(const BYTE
*in
, size_t inSize
, BYTE
*out
, size_t maxOutSize
);
474 virtual size_t decompress(const BYTE
*in
, size_t inSize
, const BYTE
**out
);
475 virtual size_t compressBufferSize(size_t dataSize
);
481 * Deflate stream compressor
483 class LIBNETXMS_EXPORTABLE DeflateStreamCompressor
: public StreamCompressor
486 z_stream_s
*m_stream
;
492 DeflateStreamCompressor(bool compress
, size_t maxBlockSize
);
493 virtual ~DeflateStreamCompressor();
495 virtual size_t compress(const BYTE
*in
, size_t inSize
, BYTE
*out
, size_t maxOutSize
);
496 virtual size_t decompress(const BYTE
*in
, size_t inSize
, const BYTE
**out
);
497 virtual size_t compressBufferSize(size_t dataSize
);
502 * NXCP message consumer interface
504 class LIBNETXMS_EXPORTABLE MessageConsumer
507 virtual SOCKET
getSocket() = 0;
508 virtual void processMessage(NXCPMessage
*msg
) = 0;
512 * Socket receiver - manages receiving NXCP messages from multiple sockets
514 class LIBNETXMS_EXPORTABLE SocketReceiver
518 HashMap
<SOCKET
, MessageConsumer
> *m_consumers
;
520 static int m_maxSocketsPerThread
;
521 static ObjectArray
<SocketReceiver
> *m_receivers
;
525 static void shutdown();
527 static void addConsumer(MessageConsumer
*mc
);
528 static void removeConsumer(MessageConsumer
*mc
);
530 static String
getDiagInfo();
534 #else /* __cplusplus */
536 typedef void NXCPMessage
;
537 typedef void NXCPEncryptionContext
;
541 typedef bool (*NXCPMessageNameResolver
)(UINT16 code
, TCHAR
*buffer
);
550 void LIBNETXMS_EXPORTABLE
NXCPInitBuffer(NXCP_BUFFER
*nxcpBuffer
);
551 int LIBNETXMS_EXPORTABLE
RecvNXCPMessage(SOCKET hSocket
, NXCP_MESSAGE
*pMsg
,
552 NXCP_BUFFER
*pBuffer
, UINT32 dwMaxMsgSize
,
553 NXCPEncryptionContext
**ppCtx
,
554 BYTE
*pDecryptionBuffer
, UINT32 dwTimeout
);
555 int LIBNETXMS_EXPORTABLE
RecvNXCPMessage(AbstractCommChannel
*channel
, NXCP_MESSAGE
*pMsg
,
556 NXCP_BUFFER
*pBuffer
, UINT32 dwMaxMsgSize
,
557 NXCPEncryptionContext
**ppCtx
,
558 BYTE
*pDecryptionBuffer
, UINT32 dwTimeout
);
559 int LIBNETXMS_EXPORTABLE
RecvNXCPMessageEx(SOCKET hSocket
, NXCP_MESSAGE
**msgBuffer
,
560 NXCP_BUFFER
*nxcpBuffer
, UINT32
*bufferSize
,
561 NXCPEncryptionContext
**ppCtx
,
562 BYTE
**decryptionBuffer
, UINT32 dwTimeout
,
564 int LIBNETXMS_EXPORTABLE
RecvNXCPMessageEx(AbstractCommChannel
*channel
, NXCP_MESSAGE
**msgBuffer
,
565 NXCP_BUFFER
*nxcpBuffer
, UINT32
*bufferSize
,
566 NXCPEncryptionContext
**ppCtx
,
567 BYTE
**decryptionBuffer
, UINT32 dwTimeout
,
569 NXCP_MESSAGE LIBNETXMS_EXPORTABLE
*CreateRawNXCPMessage(UINT16 code
, UINT32 id
, UINT16 flags
,
570 const void *data
, size_t dataSize
,
571 NXCP_MESSAGE
*buffer
, bool allowCompression
);
572 bool LIBNETXMS_EXPORTABLE
SendFileOverNXCP(SOCKET hSocket
, UINT32 dwId
, const TCHAR
*pszFile
,
573 NXCPEncryptionContext
*pCtx
, long offset
,
574 void (* progressCallback
)(INT64
, void *), void *cbArg
,
575 MUTEX mutex
, NXCPStreamCompressionMethod compressionMethod
= NXCP_STREAM_COMPRESSION_NONE
);
576 bool LIBNETXMS_EXPORTABLE
SendFileOverNXCP(AbstractCommChannel
*channel
, UINT32 dwId
, const TCHAR
*pszFile
,
577 NXCPEncryptionContext
*pCtx
, long offset
,
578 void (* progressCallback
)(INT64
, void *), void *cbArg
,
579 MUTEX mutex
, NXCPStreamCompressionMethod compressionMethod
= NXCP_STREAM_COMPRESSION_NONE
);
580 bool LIBNETXMS_EXPORTABLE
NXCPGetPeerProtocolVersion(SOCKET s
, int *pnVersion
, MUTEX mutex
);
581 bool LIBNETXMS_EXPORTABLE
NXCPGetPeerProtocolVersion(AbstractCommChannel
*channel
, int *pnVersion
, MUTEX mutex
);
583 TCHAR LIBNETXMS_EXPORTABLE
*NXCPMessageCodeName(UINT16 wCode
, TCHAR
*buffer
);
584 void LIBNETXMS_EXPORTABLE
NXCPRegisterMessageNameResolver(NXCPMessageNameResolver r
);
585 void LIBNETXMS_EXPORTABLE
NXCPUnregisterMessageNameResolver(NXCPMessageNameResolver r
);
587 bool LIBNETXMS_EXPORTABLE
InitCryptoLib(UINT32 dwEnabledCiphers
);
588 UINT32 LIBNETXMS_EXPORTABLE
NXCPGetSupportedCiphers();
589 String LIBNETXMS_EXPORTABLE
NXCPGetSupportedCiphersAsText();
590 NXCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE
*NXCPEncryptMessage(NXCPEncryptionContext
*pCtx
, NXCP_MESSAGE
*pMsg
);
591 bool LIBNETXMS_EXPORTABLE
NXCPDecryptMessage(NXCPEncryptionContext
*pCtx
,
592 NXCP_ENCRYPTED_MESSAGE
*pMsg
,
593 BYTE
*pDecryptionBuffer
);
594 UINT32 LIBNETXMS_EXPORTABLE
SetupEncryptionContext(NXCPMessage
*pMsg
,
595 NXCPEncryptionContext
**ppCtx
,
596 NXCPMessage
**ppResponse
,
597 RSA
*pPrivateKey
, int nNXCPVersion
);
598 void LIBNETXMS_EXPORTABLE
PrepareKeyRequestMsg(NXCPMessage
*pMsg
, RSA
*pServerKey
, bool useX509Format
);
599 RSA LIBNETXMS_EXPORTABLE
*LoadRSAKeys(const TCHAR
*pszKeyFile
);
600 RSA LIBNETXMS_EXPORTABLE
*RSAKeyFromData(const BYTE
*data
, size_t size
, bool withPrivate
);
601 void LIBNETXMS_EXPORTABLE
RSAFree(RSA
*key
);
604 BOOL LIBNETXMS_EXPORTABLE
SignMessageWithCAPI(BYTE
*pMsg
, UINT32 dwMsgLen
, const CERT_CONTEXT
*pCert
,
605 BYTE
*pBuffer
, size_t bufferSize
, UINT32
*pdwSigLen
);
610 #endif /* _nxcpapi_h_ */