12.10.2005 13:33:03Русский язык в запросе Ответов: 4
al
Если при создании запроса использовать поля Subject на русском языке, то в результате получаю нечитаемый текст. Подскажите, как это исправить. В проекте установлено Use Multi-Byte Character Set. Вот код (CryptoAPI):

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <wincryptex.h>
#include <atlstr.h>
#include <strsafe.h>
#include "atlenc.h"

void main(void)
{
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
CERT_RDN_ATTR rgNameAttr[1];
DWORD cbNameEncoded;
BYTE* pbNameEncoded;
HANDLE hf = NULL;
CERT_REQUEST_INFO CertReqInfo;
CRYPT_ALGORITHM_IDENTIFIER SigAlg;
DWORD dwSize;
BYTE* pbSignedEncodedCertReq;
DWORD cbPublicKeyInfo;
CERT_PUBLIC_KEY_INFO* pbPublicKeyInfo;

CString CSPName = "Crypto-Pro Cryptographic Service Provider";
LPCSTR UserName = "User";
CString CN = "абвгдеёжзийклмнопрстуфхцчшщьъэюя";

// Запрос контекста провайдера и генерация ключей
CryptAcquireContext(&hCryptProv,UserName,CSPName,2,CRYPT_NEWKEYSET);
CryptGenKey(hCryptProv,CALG_DH_EL_SF,CRYPT_EXPORTABLE,&hKey);
// Заполнение поля CN
rgNameAttr[0].pszObjId = szOID_COMMON_NAME;
rgNameAttr[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
rgNameAttr[0].Value.cbData = CN.GetLength();
rgNameAttr[0].Value.pbData = (BYTE*)malloc(CN.GetLength());
CopyMemory(rgNameAttr[0].Value.pbData,CN,CN.GetLength());
CERT_RDN rgRDN[1] = {1,&rgNameAttr[0]};
CERT_NAME_INFO Name = {1,&rgRDN[0]};
CERT_NAME_BLOB SubjNameBlob;
// Кодирование структуры CERT_NAME_INFO
CryptEncodeObject(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,X509_NAME,&Name,NULL,&cbNameEncoded);
pbNameEncoded = (BYTE*)malloc(cbNameEncoded);
CryptEncodeObject(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,X509_NAME,&Name,pbNameEncoded,&cbNameEncoded);
SubjNameBlob.cbData = cbNameEncoded;
SubjNameBlob.pbData = pbNameEncoded;
CertReqInfo.Subject = SubjNameBlob;
// Заполнение остальных параметров CERT_REQUEST_INFO
CertReqInfo.dwVersion = CERT_V1;
CertReqInfo.cAttribute = 0;
CertReqInfo.rgAttribute = NULL;
CryptExportPublicKeyInfo(hCryptProv,AT_KEYEXCHANGE,X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,NULL,&cbPublicKeyInfo);
pbPublicKeyInfo = (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo);
CryptExportPublicKeyInfo(hCryptProv,AT_KEYEXCHANGE,X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,pbPublicKeyInfo,&cbPublicKeyInfo);
CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;
// Генерация запроса
SigAlg.pszObjId = "1.2.643.2.2.4";
SigAlg.Parameters.cbData = 0;
SigAlg.Parameters.pbData = NULL;
CryptSignAndEncodeCertificate(hCryptProv,AT_KEYEXCHANGE,X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,X509_CERT_REQUEST_TO_BE_SIGNED,&CertReqInfo,&SigAlg,NULL,NULL,&dwSize);
pbSignedEncodedCertReq = (BYTE*)malloc(dwSize);
CryptSignAndEncodeCertificate(hCryptProv,AT_KEYEXCHANGE,X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,X509_CERT_REQUEST_TO_BE_SIGNED,&CertReqInfo,&SigAlg,NULL,pbSignedEncodedCertReq,&dwSize);
// Кодирование запроса в Base64
int dwSize64 = dwSize*2;
LPSTR pBase64Req = (LPSTR)malloc(dwSize64);
Base64Encode(pbSignedEncodedCertReq,dwSize,pBase64Req,&dwSize64);
// Запись в файл c:\req.req
hf = CreateFile("c:\\req.req",GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hf != INVALID_HANDLE_VALUE)
{
DWORD cbWrite;
WriteFile(hf,pBase64Req,dwSize64,&cbWrite,NULL);
}
if(hf)
CloseHandle(hf);
// Очистка памяти
free(pBase64Req);
free(pbSignedEncodedCertReq);
free(pbPublicKeyInfo);
free(pbNameEncoded);
free(rgNameAttr[0].Value.pbData);
CryptReleaseContext(hCryptProv,0);
}
 
Ответы:
13.10.2005 10:30:03Kirill Sobolev
Printable string - это строка, состоящая из символов
A, B, …, Z
a, b, …, z
0, 1, …, 9
(space) &rsquo; ( ) +, - . / : = ?
для русского языка нужно использовать юникод.
13.10.2005 10:49:12al
Пробовал и
CERT_RDN_ATTR dwValueType CERT_RDN_UNICODE_STRING
и
CryptEncodeObject(X509_UNICODE_NAME)
в разных сочетаниях, но русский текст не проходит.
13.10.2005 10:51:52Kirill Sobolev
А вот так пробовали?

USES_CONVERSION;
// Заполнение поля CN
LPWSTR s = T2W(CN);
rgNameAttr[0].pszObjId = szOID_COMMON_NAME;
rgNameAttr[0].dwValueType = CERT_RDN_UNICODE_STRING;
rgNameAttr[0].Value.cbData = wcslen(s)*sizeof(WCHAR);
rgNameAttr[0].Value.pbData = (BYTE*)s;
13.10.2005 11:27:34al
Большое спасибо, так сработало.