Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37797623
en ru br
Репозитории ALT

Группа :: Разработка/Прочее
Пакет: libpkcs11-helper

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: libpkcs11-helper-1.25.1-gost-derive.patch
Скачать


 include/pkcs11-helper-1.0/pkcs11.h       |  49 ++++++
 include/pkcs11-helper-1.0/pkcs11h-core.h |   2 +
 lib/_pkcs11h-util.h                      |  12 ++
 lib/pkcs11h-certificate.c                | 267 ++++++++++++++++++++++++++-----
 lib/pkcs11h-util.c                       |  25 +++
 5 files changed, 317 insertions(+), 38 deletions(-)
diff --git a/include/pkcs11-helper-1.0/pkcs11.h b/include/pkcs11-helper-1.0/pkcs11.h
index 2e6a1e3..9a7162c 100644
--- a/include/pkcs11-helper-1.0/pkcs11.h
+++ b/include/pkcs11-helper-1.0/pkcs11.h
@@ -329,6 +329,9 @@ typedef unsigned long ck_hw_feature_type_t;
 #define CKH_VENDOR_DEFINED	((unsigned long) (1 << 31))
 
 
+#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xD4321000 /* 0x80000000 | 0x54321000 */
+#define CK_VENDOR_PKCS11_RU_TEAM_TC26 NSSCK_VENDOR_PKCS11_RU_TEAM
+
 typedef unsigned long ck_key_type_t;
 
 #define CKK_RSA			(0)
@@ -356,6 +359,11 @@ typedef unsigned long ck_key_type_t;
 #define CKK_AES			(0x1f)
 #define CKK_BLOWFISH		(0x20)
 #define CKK_TWOFISH		(0x21)
+#define CKK_GOSTR3410		(0x30UL)
+#define CKK_GOSTR3411		(0x31UL)
+#define CKK_GOST28147		(0x32UL)
+#define CKK_GOSTR3410_256   CKK_GOSTR3410
+#define CKK_GOSTR3410_512   (CK_VENDOR_PKCS11_RU_TEAM_TC26 | 0x003)
 #define CKK_VENDOR_DEFINED	((unsigned long) (1 << 31))
 
 
@@ -669,6 +677,21 @@ typedef unsigned long ck_mechanism_type_t;
 #define CKM_AES_MAC			(0x1083)
 #define CKM_AES_MAC_GENERAL		(0x1084)
 #define CKM_AES_CBC_PAD			(0x1085)
+/* GOST */
+#define CKM_GOSTR3410_KEY_PAIR_GEN		0x00001200
+#define CKM_GOSTR3410					0x00001201
+#define CKM_GOSTR3410_WITH_GOSTR3411	0x00001202
+#define CKM_GOSTR3410_KEY_WRAP			0x00001203
+#define CKM_GOSTR3410_DERIVE			0x00001204
+#define CKM_GOSTR3411					0x00001210
+#define CKM_GOSTR3411_HMAC				0x00001211
+#define CKM_GOST28147_KEY_GEN			0x00001220
+#define CKM_GOST28147_ECB				0x00001221
+#define CKM_GOST28147					0x00001222
+#define CKM_GOST28147_MAC				0x00001223
+#define CKM_GOST28147_KEY_WRAP			0x00001224
+#define CKM_GOSTR3410_12_DERIVE         (CK_VENDOR_PKCS11_RU_TEAM_TC26 | 0x007)
+/* Other */
 #define CKM_DSA_PARAMETER_GEN		(0x2000)
 #define CKM_DH_PKCS_PARAMETER_GEN	(0x2001)
 #define CKM_X9_42_DH_PARAMETER_GEN	(0x2002)
@@ -1354,4 +1377,30 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
 }
 #endif
 
+/* Flags and structures for Key derivation */
+#define CKD_NULL                 0x00000001
+#define CKD_SHA1_KDF             0x00000002
+#define CKD_SHA1_KDF_ASN1        0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+#define CKD_SHA224_KDF           0x00000005
+#define CKD_SHA256_KDF           0x00000006
+#define CKD_SHA384_KDF           0x00000007
+#define CKD_SHA512_KDF           0x00000008
+
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+	unsigned long  kdf;
+	unsigned long  ulSharedDataLen;
+	unsigned char *  pSharedData;
+	unsigned long  ulPublicDataLen;
+	unsigned char *  pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef struct CK_GOSTR3410_DERIVE_PARAMS {
+	CK_ULONG kdf;
+	CK_BYTE *pPublicData;
+	CK_ULONG ulPublicDataLen;
+	CK_BYTE *pUKM;
+	CK_ULONG ulUKMLen;
+} CK_GOSTR3410_DERIVE_PARAMS;
+
 #endif	/* PKCS11_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-core.h b/include/pkcs11-helper-1.0/pkcs11h-core.h
index 90632f5..6873e39 100644
--- a/include/pkcs11-helper-1.0/pkcs11h-core.h
+++ b/include/pkcs11-helper-1.0/pkcs11h-core.h
@@ -153,6 +153,8 @@ extern "C" {
 #define PKCS11H_PRIVATEMODE_MASK_DECRYPT	(1<<2)
 /** Force unwrap. */
 #define PKCS11H_PRIVATEMODE_MASK_UNWRAP		(1<<3)
+/** Force derive. */
+#define PKCS11H_PRIVATEMODE_MASK_DERIVE		(1<<4)
 /** @} */
 
 /**
diff --git a/lib/_pkcs11h-util.h b/lib/_pkcs11h-util.h
index e9237af..5e98594 100644
--- a/lib/_pkcs11h-util.h
+++ b/lib/_pkcs11h-util.h
@@ -92,5 +92,17 @@ _pkcs11h_util_unescapeString (
 	IN size_t * const max
 );
 
+void
+_pkcs11h_util_flip_buf (
+	IN OUT CK_BYTE_PTR buf,
+	IN CK_ULONG len
+);
+
+void
+_pkcs11h_util_put_lsb32 (
+	OUT CK_BYTE_PTR buf,
+	IN CK_ULONG val
+);
+
 #endif
 
diff --git a/lib/pkcs11h-certificate.c b/lib/pkcs11h-certificate.c
index 92a3c45..67b26fd 100644
--- a/lib/pkcs11h-certificate.c
+++ b/lib/pkcs11h-certificate.c
@@ -60,12 +60,14 @@
 #include "_pkcs11h-session.h"
 #include "_pkcs11h-token.h"
 #include "_pkcs11h-certificate.h"
+#include "_pkcs11h-util.h"
 
 enum __pkcs11h_private_op_e {
 	__pkcs11h_private_op_sign=0,
 	__pkcs11h_private_op_sign_recover,
 	__pkcs11h_private_op_decrypt,
-	__pkcs11h_private_op_unwrap
+	__pkcs11h_private_op_unwrap,
+	__pkcs11h_private_op_derive
 };
 
 static
@@ -476,7 +478,8 @@ __pkcs11h_certificate_getKeyAttributes (
 			{CKA_SIGN, NULL, 0},
 			{CKA_SIGN_RECOVER, NULL, 0},
 			{CKA_DECRYPT, NULL, 0},
-			{CKA_UNWRAP, NULL, 0}
+			{CKA_UNWRAP, NULL, 0},
+			{CKA_DERIVE, NULL, 0}
 		};
 
 		/*
@@ -502,6 +505,7 @@ __pkcs11h_certificate_getKeyAttributes (
 			CK_BBOOL *key_attrs_sign_recover;
 			CK_BBOOL *key_attrs_decrypt;
 			CK_BBOOL *key_attrs_unwrap;
+			CK_BBOOL *key_attrs_derive;
 
 			if (
 				(rv = _pkcs11h_session_getObjectAttributes (
@@ -518,6 +522,7 @@ __pkcs11h_certificate_getKeyAttributes (
 			key_attrs_sign_recover = (CK_BBOOL *)key_attrs[1].pValue;
 			key_attrs_decrypt = (CK_BBOOL *)key_attrs[2].pValue;
 			key_attrs_unwrap = (CK_BBOOL *)key_attrs[3].pValue;
+			key_attrs_derive = (CK_BBOOL *)key_attrs[4].pValue;
 
 			if (key_attrs_sign != NULL && *key_attrs_sign != CK_FALSE) {
 				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_SIGN;
@@ -531,6 +536,9 @@ __pkcs11h_certificate_getKeyAttributes (
 			if (key_attrs_unwrap != NULL && *key_attrs_unwrap != CK_FALSE) {
 				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_UNWRAP;
 			}
+			if (key_attrs_derive != NULL && *key_attrs_derive != CK_FALSE) {
+				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_DERIVE;
+			}
 			if (certificate->mask_private_mode == 0) {
 				rv = CKR_KEY_TYPE_INCONSISTENT;
 				goto retry;
@@ -790,20 +798,26 @@ __pkcs11h_certificate_doPrivateOperation (
 		mech_type, NULL, 0
 	};
 
-/*	CK_BBOOL wrap_attrs_false = CK_FALSE; */
-	CK_BBOOL wrap_attrs_true = CK_TRUE;
+	CK_BBOOL result_attrs_false = CK_FALSE;
+	CK_BBOOL result_attrs_true = CK_TRUE;
 	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
 	CK_KEY_TYPE keytype = CKK_GENERIC_SECRET;
-	CK_ATTRIBUTE wrap_attrs[] = {
+	CK_ATTRIBUTE result_attrs[] = {
 		{CKA_CLASS, &class, sizeof (class)},
 		{CKA_KEY_TYPE, &keytype, sizeof (keytype)},
-		{CKA_EXTRACTABLE, &wrap_attrs_true, sizeof (wrap_attrs_true)}
-/* OpenSC fail!	{CKA_TOKEN, &wrap_attrs_false, sizeof (wrap_attrs_false)} */
+		{CKA_EXTRACTABLE, &result_attrs_true, sizeof (result_attrs_true)},
+		{CKA_TOKEN, &result_attrs_false, sizeof (result_attrs_false)},
+		{CKA_MODIFIABLE, &result_attrs_true, sizeof (result_attrs_true)},
+		{CKA_PRIVATE, &result_attrs_false, sizeof (result_attrs_false)},
+		{CKA_SENSITIVE, &result_attrs_false, sizeof (result_attrs_false)}
 	};
-	CK_ATTRIBUTE wrap_value[] = {
+	CK_ATTRIBUTE result_value[] = {
 		{CKA_VALUE, target, 0}
 	};
-	CK_OBJECT_HANDLE wrap_key = _PKCS11H_INVALID_OBJECT_HANDLE;
+	CK_OBJECT_HANDLE result_key = _PKCS11H_INVALID_OBJECT_HANDLE;
+
+	CK_ECDH1_DERIVE_PARAMS ecdh_params;
+	CK_GOSTR3410_DERIVE_PARAMS gost3410_derive_params;
 
 	CK_RV rv = CKR_FUNCTION_FAILED;
 	PKCS11H_BOOL login_retry = FALSE;
@@ -876,9 +890,91 @@ __pkcs11h_certificate_doPrivateOperation (
 						certificate->key_handle,
 						(CK_BYTE_PTR)source,
 						source_size,
-						wrap_attrs,
-						sizeof (wrap_attrs) / sizeof (CK_ATTRIBUTE),
-						&wrap_key
+						result_attrs,
+						sizeof (result_attrs) / sizeof (CK_ATTRIBUTE),
+						&result_key
+					);
+				break;
+				case __pkcs11h_private_op_derive:
+					switch (mech_type) {
+					case CKM_GOSTR3410_DERIVE:
+						memset (&gost3410_derive_params, 0,
+								sizeof (gost3410_derive_params));
+						gost3410_derive_params.kdf = CKD_NULL;
+						gost3410_derive_params.ulPublicDataLen = 64;
+						gost3410_derive_params.pPublicData = (CK_BYTE_PTR) source;
+						gost3410_derive_params.ulUKMLen = source_size - 64;
+						gost3410_derive_params.pUKM = (CK_BYTE_PTR) (source + 64);
+						mech.pParameter = &gost3410_derive_params;
+						mech.ulParameterLen = sizeof (gost3410_derive_params);
+						keytype = CKK_GOST28147;
+					break;
+					case CKM_GOSTR3410_12_DERIVE: {
+						CK_KEY_TYPE pkey_type;
+						CK_ATTRIBUTE _attrs[] = {
+							{CKA_KEY_TYPE, &pkey_type, sizeof (pkey_type)}
+						};
+						rv = certificate->session->provider->f->
+							C_GetAttributeValue (
+								certificate->session->session_handle,
+								certificate->key_handle,
+								_attrs,
+								sizeof (_attrs) / sizeof (CK_ATTRIBUTE)
+							);
+						if (rv != CKR_OK)
+							goto retry;
+
+						unsigned int key_len;
+						switch (pkey_type) {
+						case CKK_GOSTR3410_256:
+							key_len = 64;
+						break;
+						case CKK_GOSTR3410_512:
+							key_len = 128;
+						break;
+						default:
+							rv = CKR_KEY_TYPE_INCONSISTENT;
+							goto cleanup;
+						}
+
+						/* Maximum supported UKM length is 32 bytes */
+						if (source_size - key_len > 32) {
+							rv = CKR_ARGUMENTS_BAD;
+							goto cleanup;
+						}
+
+						CK_BYTE gost3410_12_derive_params[8 + 128 + 4 + 32];
+						_pkcs11h_util_put_lsb32 (gost3410_12_derive_params, CKD_NULL);
+						_pkcs11h_util_put_lsb32 (gost3410_12_derive_params + 4, key_len);
+						memcpy (gost3410_12_derive_params + 8, source, key_len);
+						_pkcs11h_util_put_lsb32 (gost3410_12_derive_params + 8 + key_len,
+												 source_size - key_len);
+						memcpy (gost3410_12_derive_params + 8 + key_len + 4,
+								source + key_len, source_size - key_len);
+
+						mech.pParameter = &gost3410_12_derive_params;
+						mech.ulParameterLen = 8 + key_len + 4 + source_size - key_len;
+						keytype = CKK_GOST28147;
+					}
+					break;
+					default:
+						memset (&ecdh_params, 0, sizeof (ecdh_params));
+						ecdh_params.kdf = CKD_NULL;
+						ecdh_params.ulPublicDataLen = source_size;
+						ecdh_params.pPublicData = (CK_BYTE_PTR) source;
+						// TODO: Split the source on public / shared.
+						ecdh_params.ulSharedDataLen = 0;
+						ecdh_params.pSharedData = NULL;
+						mech.pParameter = &ecdh_params;
+						mech.ulParameterLen = sizeof (ecdh_params);
+					}
+					rv = certificate->session->provider->f->C_DeriveKey (
+						certificate->session->session_handle,
+						&mech,
+						certificate->key_handle,
+						result_attrs,
+						sizeof (result_attrs) / sizeof (CK_ATTRIBUTE),
+						&result_key
 					);
 				break;
 				default:
@@ -933,16 +1029,17 @@ __pkcs11h_certificate_doPrivateOperation (
 				);
 			break;
 			case __pkcs11h_private_op_unwrap:
-				wrap_value[0].ulValueLen = size;
-
+			case __pkcs11h_private_op_derive:
+				result_value[0].ulValueLen = size;
+				
 				rv = certificate->session->provider->f->C_GetAttributeValue (
 					certificate->session->session_handle,
-					wrap_key,
-					wrap_value,
-					sizeof (wrap_value) / sizeof (CK_ATTRIBUTE)
+					result_key,
+					result_value,
+					sizeof (result_value) / sizeof (CK_ATTRIBUTE)
 				);
 
-				size = wrap_value[0].ulValueLen;
+				size = result_value[0].ulValueLen;
 			break;
 			default:
 				rv = CKR_ARGUMENTS_BAD;
@@ -960,7 +1057,10 @@ __pkcs11h_certificate_doPrivateOperation (
 			rv
 		);
 
-		if (rv == CKR_BUFFER_TOO_SMALL && op != __pkcs11h_private_op_unwrap) {
+		if (rv == CKR_BUFFER_TOO_SMALL &&
+			op != __pkcs11h_private_op_unwrap &&
+			op != __pkcs11h_private_op_derive)
+		{
 			certificate->operation_active = TRUE;
 		}
 
@@ -971,7 +1071,9 @@ __pkcs11h_certificate_doPrivateOperation (
 		}
 		else {
 			if (rv == CKR_OK) {
-				if (op != __pkcs11h_private_op_unwrap) {
+				if (op != __pkcs11h_private_op_unwrap &&
+					op != __pkcs11h_private_op_derive)
+				{
 					certificate->operation_active = TRUE;
 				}
 			}
@@ -985,12 +1087,12 @@ __pkcs11h_certificate_doPrivateOperation (
 
 	retry:
 
-		if (wrap_key != _PKCS11H_INVALID_OBJECT_HANDLE) {
+		if (result_key != _PKCS11H_INVALID_OBJECT_HANDLE) {
 			certificate->session->provider->f->C_DestroyObject (
 				certificate->session->session_handle,
-				wrap_key
+				result_key
 			);
-			wrap_key = _PKCS11H_INVALID_OBJECT_HANDLE;
+			result_key = _PKCS11H_INVALID_OBJECT_HANDLE;
 		}
 
 		if (!op_succeed) {
@@ -1545,6 +1647,68 @@ cleanup:
 }
 
 CK_RV
+pkcs11h_certificate_derive (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_FUNCTION_FAILED;
+
+	_PKCS11H_ASSERT (_g_pkcs11h_data!=NULL);
+	_PKCS11H_ASSERT (_g_pkcs11h_data->initialized);
+	_PKCS11H_ASSERT (certificate!=NULL);
+	_PKCS11H_ASSERT (source!=NULL);
+	/*_PKCS11H_ASSERT (target); NOT NEEDED*/
+	_PKCS11H_ASSERT (p_target_size!=NULL);
+
+	_PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_derive entry certificate=%p, mech_type=%ld, source=%p, source_size="P_Z", target=%p, *p_target_size="P_Z"",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+	if (
+		(rv = __pkcs11h_certificate_doPrivateOperation (
+			certificate,
+			__pkcs11h_private_op_derive,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		)) != CKR_OK
+	) {
+		goto cleanup;
+	}
+
+	rv = CKR_OK;
+
+cleanup:
+
+	_PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_derive return rv=%lu-'%s', *p_target_size="P_Z"",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}	
+
+CK_RV
 pkcs11h_certificate_signAny (
 	IN const pkcs11h_certificate_t certificate,
 	IN const CK_MECHANISM_TYPE mech_type,
@@ -1585,6 +1749,8 @@ pkcs11h_certificate_signAny (
 		}
 	}
 
+	rv = CKR_FUNCTION_FAILED;
+
 	if (
 		!acked &&
 		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_SIGN) != 0
@@ -1639,15 +1805,12 @@ pkcs11h_certificate_signAny (
 		}
 	}
 
-	if (!acked) {
+cleanup:
+
+	if (!acked && (rv == CKR_OK)) {
 		rv = CKR_FUNCTION_FAILED;
-		goto cleanup;
 	}
 
-	rv = CKR_OK;
-
-cleanup:
-
 	_PKCS11H_DEBUG (
 		PKCS11H_LOG_DEBUG2,
 		"PKCS#11: pkcs11h_certificate_signAny return rv=%lu-'%s', *p_target_size="P_Z"",
@@ -1699,19 +1862,21 @@ pkcs11h_certificate_decryptAny (
 		}
 	}
 
+	rv = CKR_FUNCTION_FAILED;
+
 	if (
 		!acked &&
 		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_DECRYPT) != 0
 	) {
 		switch (
-			pkcs11h_certificate_decrypt (
+			(rv = pkcs11h_certificate_decrypt (
 				certificate,
 				mech_type,
 				source,
 				source_size,
 				target,
 				p_target_size
-			)
+			))
 		) {
 			case CKR_OK:
 				acked = TRUE;
@@ -1731,14 +1896,14 @@ pkcs11h_certificate_decryptAny (
 		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_UNWRAP) != 0
 	) {
 		switch (
-			pkcs11h_certificate_unwrap (
+			(rv = pkcs11h_certificate_unwrap (
 				certificate,
 				mech_type,
 				source,
 				source_size,
 				target,
 				p_target_size
-			)
+			))
 		) {
 			case CKR_OK:
 				acked = TRUE;
@@ -1753,15 +1918,41 @@ pkcs11h_certificate_decryptAny (
 		}
 	}
 
-	if (!acked) {
-		rv = CKR_FUNCTION_FAILED;
-		goto cleanup;
+	/* Make key derivation to be the case of decryption in accoudance
+     * with decrypt_raw() function in the ECC part of Libgcrypt. */
+	if (
+		!acked &&
+		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_DERIVE) != 0
+	) {
+		switch (
+			(rv = pkcs11h_certificate_derive (
+				certificate,
+				mech_type,
+				source,
+				source_size,
+				target,
+				p_target_size
+			))
+		) {
+			case CKR_OK:
+				acked = TRUE;
+			break;
+			case CKR_FUNCTION_NOT_SUPPORTED:
+			case CKR_KEY_FUNCTION_NOT_PERMITTED:
+			case CKR_KEY_TYPE_INCONSISTENT:
+				certificate->mask_private_mode &= ~PKCS11H_PRIVATEMODE_MASK_DERIVE;
+			break;
+			default:
+				goto cleanup;
+		}
 	}
 
-	rv = CKR_OK;
-
 cleanup:
 
+	if (!acked && (rv == CKR_OK)) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+
 	_PKCS11H_DEBUG (
 		PKCS11H_LOG_DEBUG2,
 		"PKCS#11: pkcs11h_certificate_decryptAny return rv=%lu-'%s', *p_target_size="P_Z"",
diff --git a/lib/pkcs11h-util.c b/lib/pkcs11h-util.c
index 7325db4..8d2a512 100644
--- a/lib/pkcs11h-util.c
+++ b/lib/pkcs11h-util.c
@@ -51,6 +51,9 @@
 #include "common.h"
 #include "_pkcs11h-util.h"
 
+// For byte order
+#include <arpa/inet.h>
+
 void
 _pkcs11h_util_fixupFixedString (
 	OUT char * const target,			/* MUST BE >= length+1 */
@@ -287,3 +290,25 @@ cleanup:
 	return rv;
 }
 
+void
+_pkcs11h_util_flip_buf (
+	IN OUT CK_BYTE_PTR buf,
+	IN CK_ULONG len
+) {
+	CK_ULONG tmp, i;
+
+	for (i = 0; i < len/2; i++) {
+	  tmp = buf[i];
+	  buf[i] = buf[len - 1 -i];
+	  buf[len - 1 - i] = tmp;
+	}
+}
+
+void
+_pkcs11h_util_put_lsb32 (
+	OUT CK_BYTE_PTR buf,
+	IN CK_ULONG val
+) {
+	*((uint32_t *) buf) = htonl ((uint32_t) val);
+	_pkcs11h_util_flip_buf (buf, 4);
+}
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin