| /* |
| * Copyright 2006 Juan Lang for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wincrypt.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); |
| |
| DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, |
| LPSTR psz, DWORD csz) |
| { |
| DWORD ret = 0; |
| |
| TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz); |
| |
| switch (dwValueType) |
| { |
| case CERT_RDN_ANY_TYPE: |
| break; |
| case CERT_RDN_PRINTABLE_STRING: |
| case CERT_RDN_IA5_STRING: |
| if (!psz || !csz) |
| ret = pValue->cbData; |
| else |
| { |
| DWORD chars = min(pValue->cbData, csz - 1); |
| |
| if (chars) |
| { |
| memcpy(psz, pValue->pbData, chars); |
| ret += chars; |
| csz -= chars; |
| } |
| } |
| break; |
| default: |
| FIXME("string type %ld unimplemented\n", dwValueType); |
| } |
| if (psz && csz) |
| { |
| *(psz + ret) = '\0'; |
| csz--; |
| ret++; |
| } |
| else |
| ret++; |
| return ret; |
| } |
| |
| DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, |
| LPWSTR psz, DWORD csz) |
| { |
| DWORD ret = 0; |
| |
| TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz); |
| |
| switch (dwValueType) |
| { |
| case CERT_RDN_ANY_TYPE: |
| break; |
| case CERT_RDN_PRINTABLE_STRING: |
| case CERT_RDN_IA5_STRING: |
| if (!psz || !csz) |
| ret = pValue->cbData; |
| else |
| { |
| DWORD chars = min(pValue->cbData, csz - 1); |
| |
| if (chars) |
| { |
| DWORD i; |
| |
| for (i = 0; i < chars; i++) |
| psz[i] = pValue->pbData[i]; |
| ret += chars; |
| csz -= chars; |
| } |
| } |
| break; |
| default: |
| FIXME("string type %ld unimplemented\n", dwValueType); |
| } |
| if (psz && csz) |
| { |
| *(psz + ret) = '\0'; |
| csz--; |
| ret++; |
| } |
| else |
| ret++; |
| return ret; |
| } |
| |
| |
| DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, |
| DWORD dwStrType, LPSTR psz, DWORD csz) |
| { |
| static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | |
| CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; |
| static const char commaSep[] = ", "; |
| static const char semiSep[] = "; "; |
| static const char crlfSep[] = "\r\n"; |
| static const char plusSep[] = " + "; |
| static const char spaceSep[] = " "; |
| DWORD ret = 0, bytes = 0; |
| BOOL bRet; |
| CERT_NAME_INFO *info; |
| |
| TRACE("(%ld, %p, %p, %ld)\n", dwCertEncodingType, pName, psz, csz); |
| if (dwStrType & unsupportedFlags) |
| FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags); |
| |
| bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData, |
| pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes); |
| if (bRet) |
| { |
| DWORD i, j, sepLen, rdnSepLen; |
| LPCSTR sep, rdnSep; |
| |
| if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) |
| sep = semiSep; |
| else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) |
| sep = crlfSep; |
| else |
| sep = commaSep; |
| sepLen = strlen(sep); |
| if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG) |
| rdnSep = spaceSep; |
| else |
| rdnSep = plusSep; |
| rdnSepLen = strlen(rdnSep); |
| for (i = 0; ret < csz && i < info->cRDN; i++) |
| { |
| for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++) |
| { |
| DWORD chars; |
| |
| if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR) |
| { |
| /* - 1 is needed to account for the NULL terminator. */ |
| chars = min( |
| lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId), |
| csz - ret - 1); |
| if (psz && chars) |
| memcpy(psz + ret, info->rgRDN[i].rgRDNAttr[j].pszObjId, |
| chars); |
| ret += chars; |
| csz -= chars; |
| if (csz > 1) |
| { |
| if (psz) |
| *(psz + ret) = '='; |
| ret++; |
| csz--; |
| } |
| } |
| /* FIXME: handle quoting */ |
| chars = CertRDNValueToStrA( |
| info->rgRDN[i].rgRDNAttr[j].dwValueType, |
| &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, |
| csz - ret - 1); |
| if (chars) |
| ret += chars - 1; |
| if (j < info->rgRDN[i].cRDNAttr - 1) |
| { |
| if (psz && ret < csz - rdnSepLen - 1) |
| memcpy(psz + ret, rdnSep, rdnSepLen); |
| ret += rdnSepLen; |
| } |
| } |
| if (i < info->cRDN - 1) |
| { |
| if (psz && ret < csz - sepLen - 1) |
| memcpy(psz + ret, sep, sepLen); |
| ret += sepLen; |
| } |
| } |
| LocalFree(info); |
| } |
| if (psz && csz) |
| { |
| *(psz + ret) = '\0'; |
| csz--; |
| ret++; |
| } |
| else |
| ret++; |
| return ret; |
| } |
| |
| DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, |
| DWORD dwStrType, LPWSTR psz, DWORD csz) |
| { |
| static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | |
| CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; |
| static const WCHAR commaSep[] = { ',',' ',0 }; |
| static const WCHAR semiSep[] = { ';',' ',0 }; |
| static const WCHAR crlfSep[] = { '\r','\n',0 }; |
| static const WCHAR plusSep[] = { ' ','+',' ',0 }; |
| static const WCHAR spaceSep[] = { ' ',0 }; |
| DWORD ret = 0, bytes = 0; |
| BOOL bRet; |
| CERT_NAME_INFO *info; |
| |
| TRACE("(%ld, %p, %p, %ld)\n", dwCertEncodingType, pName, psz, csz); |
| if (dwStrType & unsupportedFlags) |
| FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags); |
| |
| bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData, |
| pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes); |
| if (bRet) |
| { |
| DWORD i, j, sepLen, rdnSepLen; |
| LPCWSTR sep, rdnSep; |
| |
| if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) |
| sep = semiSep; |
| else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) |
| sep = crlfSep; |
| else |
| sep = commaSep; |
| sepLen = lstrlenW(sep); |
| if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG) |
| rdnSep = spaceSep; |
| else |
| rdnSep = plusSep; |
| rdnSepLen = lstrlenW(rdnSep); |
| for (i = 0; ret < csz && i < info->cRDN; i++) |
| { |
| for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++) |
| { |
| DWORD chars; |
| |
| if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR) |
| { |
| /* - 1 is needed to account for the NULL terminator. */ |
| chars = min( |
| lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId), |
| csz - ret - 1); |
| if (psz && chars) |
| { |
| DWORD k; |
| |
| for (k = 0; k < chars; k++) |
| *(psz + ret + k) = |
| info->rgRDN[i].rgRDNAttr[j].pszObjId[k]; |
| } |
| ret += chars; |
| csz -= chars; |
| if (csz > 1) |
| { |
| if (psz) |
| *(psz + ret) = '='; |
| ret++; |
| csz--; |
| } |
| } |
| /* FIXME: handle quoting */ |
| chars = CertRDNValueToStrW( |
| info->rgRDN[i].rgRDNAttr[j].dwValueType, |
| &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, |
| csz - ret - 1); |
| if (chars) |
| ret += chars - 1; |
| if (j < info->rgRDN[i].cRDNAttr - 1) |
| { |
| if (psz && ret < csz - rdnSepLen - 1) |
| memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR)); |
| ret += rdnSepLen; |
| } |
| } |
| if (i < info->cRDN - 1) |
| { |
| if (psz && ret < csz - sepLen - 1) |
| memcpy(psz + ret, sep, sepLen * sizeof(WCHAR)); |
| ret += sepLen; |
| } |
| } |
| LocalFree(info); |
| } |
| if (psz && csz) |
| { |
| *(psz + ret) = '\0'; |
| csz--; |
| ret++; |
| } |
| else |
| ret++; |
| return ret; |
| } |