//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: check7f.cpp // // Contents: Cert Server test for ASN-encoded 7f length // //--------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include "csdisp.h" typedef struct _ASNTABLE { WORD State; WORD Flags; WCHAR const *pwszElement; } ASNTABLE; #define BOOLEAN_TAG 0x01 #define INTEGER_TAG 0x02 #define BIT_STRING_TAG 0x03 #define OCTET_STRING_TAG 0x04 #define NULL_TAG 0x05 #define OBJECT_ID_TAG 0x06 #define SET_OF_TAG 0x11 #define PRINTABLE_STRING_TAG 0x13 #define TELETEX_STRING_TAG 0x14 #define CHAR_STRING_TAG 0x16 #define UTCTIME_TAG 0x17 #define SEQUENCE_TAG 0x30 #define RDN_TAG 0x31 #define PRIMITIVE_TAG 0x80 #define ATTRIBUTE_TAG 0xa0 #define BEG_REPEAT1 0x00000100 // begin repeat section #define BEG_REPEAT2 0x00000200 // begin nested repeat section #define END_REPEAT1 0x00000400 // 'or' in back step count #define END_REPEAT2 0x00000800 // 'or' in back step count #define OPTIONAL_FIELD 0x00001000 // begin optional field #define ANY_TAG 0x00002000 // match any tag const ASNTABLE asnCert[] = { { CHECK7F_OTHER, SEQUENCE_TAG, L"Certificate" }, { CHECK7F_OTHER, SEQUENCE_TAG, L".ToBeSigned" }, { CHECK7F_OTHER, ATTRIBUTE_TAG | OPTIONAL_FIELD, L"..Version" }, { CHECK7F_OTHER, INTEGER_TAG , L"...Version.Integer" }, { CHECK7F_OTHER, INTEGER_TAG, L"..SerialNumber" }, { CHECK7F_OTHER, SEQUENCE_TAG, L"..SignatureAlgorithm" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L"...SignatureAlgorithm.ObjectId" }, { CHECK7F_OTHER, ANY_TAG | OPTIONAL_FIELD, L"...SignatureAlgorithm.Parameters" }, { CHECK7F_ISSUER, SEQUENCE_TAG, L"..Issuer Name" }, { CHECK7F_ISSUER_RDN, BEG_REPEAT1 | RDN_TAG | OPTIONAL_FIELD, L"...Issuer.RDN" }, { CHECK7F_ISSUER_RDN_ATTRIBUTE, BEG_REPEAT2 | SEQUENCE_TAG, L"....Issuer.RDN.Attribute" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L".....Issuer.RDN.Attribute.ObjectId" }, { CHECK7F_ISSUER_RDN_STRING, ANY_TAG, L".....Issuer.RDN.Attribute.Value" }, { 0, END_REPEAT2 | 3, L"...." }, { 0, END_REPEAT1 | 5, L"..." }, { CHECK7F_OTHER, SEQUENCE_TAG, L"..Dates" }, { CHECK7F_OTHER, UTCTIME_TAG, L"...Dates.NotBefore" }, { CHECK7F_OTHER, UTCTIME_TAG, L"...Dates.NotAfter" }, { CHECK7F_SUBJECT, SEQUENCE_TAG, L"..Subject Name" }, { CHECK7F_SUBJECT_RDN, BEG_REPEAT1 | RDN_TAG | OPTIONAL_FIELD, L"...Subject.RDN" }, { CHECK7F_SUBJECT_RDN_ATTRIBUTE, BEG_REPEAT2 | SEQUENCE_TAG, L"....Subject.RDN.Attribute" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L".....Subject.RDN.Attribute.ObjectId" }, { CHECK7F_SUBJECT_RDN_STRING, ANY_TAG, L".....Subject.RDN.Attribute.Value" }, { 0, END_REPEAT2 | 3, L"...." }, { 0, END_REPEAT1 | 5, L"..." }, { CHECK7F_OTHER, SEQUENCE_TAG, L"..PublicKey" }, { CHECK7F_OTHER, SEQUENCE_TAG, L"...PublicKey.Algorithm" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L"....PublicKey.Algorithm.ObjectId" }, { CHECK7F_OTHER, ANY_TAG | OPTIONAL_FIELD, L"....PublicKey.Algorithm.Parameters" }, { CHECK7F_OTHER, BIT_STRING_TAG, L"...PublicKey.Key" }, { CHECK7F_OTHER, PRIMITIVE_TAG | 1 | OPTIONAL_FIELD, L"..IssuerUniqueId" }, { CHECK7F_OTHER, PRIMITIVE_TAG | 2 | OPTIONAL_FIELD, L"..SubjectUniqueId" }, { CHECK7F_EXTENSIONS, ATTRIBUTE_TAG | 3 | OPTIONAL_FIELD, L"..Extensions" }, { CHECK7F_EXTENSION_ARRAY, SEQUENCE_TAG, L"...Extensions.Array" }, { CHECK7F_EXTENSION, BEG_REPEAT1 | SEQUENCE_TAG, L"....Extensions.Array.Extension" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L".....Extensions.Array.Extension.ObjectId" }, { CHECK7F_OTHER, BOOLEAN_TAG | OPTIONAL_FIELD, L".....Extensions.Array.Extension.Critical" }, { CHECK7F_EXTENSION_VALUE, OCTET_STRING_TAG, L".....Extensions.Array.Extension.Value" }, //{ CHECK7F_EXTENSION_VALUE_RAW, ANY_TAG, L"......Extensions.Array.Extension.Value.Bits" }, { 0, END_REPEAT1 | 4, L"...." }, { CHECK7F_OTHER, SEQUENCE_TAG, L".SignatureAlogorithm" }, { CHECK7F_OTHER, OBJECT_ID_TAG, L"..SignatureAlgorithm.ObjectId" }, { CHECK7F_OTHER, ANY_TAG | OPTIONAL_FIELD, L"..SignatureAlgorithm.Parameters" }, { CHECK7F_OTHER, BIT_STRING_TAG, L".Signature" }, { 0, 0, NULL } }; #define cbOLDCERTENROLLCHOKESLENGTH 0x7f // DecodeLength decodes an ASN1 encoded length field. The pbEncoded parameter // is the encoded length. pdwLen is used to return the length. The function // returns a -1 if it fails and otherwise returns the number of total bytes in // the encoded length. long DecodeLength( BOOL fVerbose, DWORD *pdwLen, DWORD iLevel, BYTE const *pbBase, BYTE const *pbEncoded, DWORD cbEncoded, WCHAR const *pwsz) { long index = 0; BYTE count; assert(NULL != pdwLen); assert(NULL != pbEncoded); if (1 > cbEncoded) { DBGPRINT((DBG_SS_CERTLIB, "cbEncoded overflow %d\n", cbEncoded)); return(-1); } // determine the length of the length field count = pbEncoded[0]; if (0x80 < count) { // If there is more than one byte in the length field, then the lower // seven bits tells us the number of bytes. count &= 0x7f; // This function only allows the length field to be 2 bytes. If the // field is longer, then the function fails. if (2 < count) { DBGPRINT((DBG_SS_CERTLIB, "Length field reported to be over 2 bytes\n")); return(-1); } if (count > cbEncoded) { DBGPRINT((DBG_SS_CERTLIB, "cbEncoded overflow %d\n", cbEncoded)); return(-1); } *pdwLen = 0; // go through the bytes of the length field for (index = 1; index <= count; index++) { *pdwLen = (*pdwLen << 8) + pbEncoded[index]; } } else // the length field is just one byte long { *pdwLen = pbEncoded[0]; index = 1; } // return how many bytes there were in the length field. #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT7(( DBG_SS_CERTLIB, "asn %u:@%x: %02x, len %x, cbEncoded %x, end @%x, %ws\n", iLevel, &pbEncoded[-1] - pbBase, pbEncoded[-1], *pdwLen, cbEncoded + 1, &pbEncoded[-1] - pbBase + cbEncoded + 1, pwsz)); } #endif // DBG_CERTSRV return(index); } WCHAR const * GetLevel( OPTIONAL IN WCHAR const *pwszField, OUT DWORD *piLevel) { DWORD iLevel = 0; iLevel = 0; if (NULL != pwszField) { while ('.' == *pwszField) { iLevel++; pwszField++; } } *piLevel = iLevel; return(pwszField); } BOOL RestoreLevel( IN DWORD *acbLevel, IN DWORD iLevelNext, IN DWORD *piLevel, IN BOOL fVerbose) { BOOL fOk = FALSE; DWORD iLevel; DWORD i = *piLevel; #if DBG_CERTSRV if (1 < fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIBI, "RestoreLevel(%x, %x)\n", iLevelNext, *piLevel)); } #endif iLevel = *piLevel; while (0 < iLevel && 0 == acbLevel[iLevel] && iLevelNext < iLevel) { iLevel--; if (1 < fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIBI, "Restoring length(%u) ==> %x\n", iLevel, acbLevel[iLevel])); } } if (iLevelNext < iLevel) { CONSOLEPRINT2(( MAXDWORD, "BAD RESTORED LENGTH[%u]: 0 < %x\n", iLevel, acbLevel[iLevel])); goto error; } *piLevel = iLevel; fOk = TRUE; error: if (1 < fVerbose) { CONSOLEPRINT4(( DBG_SS_CERTLIBI, "RestoreLevel(%x, %x --> %x) --> %x\n", iLevelNext, i, *piLevel, fOk)); } return(fOk); } VOID ReturnString( IN WCHAR const *pwszReturn, OPTIONAL IN OUT DWORD *pcwcBuf, OPTIONAL OUT WCHAR *pwcBuf) { DWORD cwcNeeded = wcslen(pwszReturn) + 1; DWORD cwcBuf; if (NULL != pcwcBuf) { cwcBuf = *pcwcBuf; if (NULL != pwcBuf && 0 < cwcBuf) { CopyMemory(pwcBuf, pwszReturn, sizeof(WCHAR) * min(cwcBuf, cwcNeeded)); pwcBuf[cwcBuf - 1] = L'\0'; } *pcwcBuf = cwcNeeded; } } #define MATCHTAG(b, flags) ((ANY_TAG & (flags)) || (b) == (BYTE) (flags)) HRESULT myCheck7f( IN const BYTE *pbCert, IN DWORD cbCert, IN BOOL fVerbose, OUT DWORD *pState, OPTIONAL OUT DWORD *pIndex1, OPTIONAL OUT DWORD *pIndex2, OPTIONAL IN OUT DWORD *pcwcField, OPTIONAL OUT WCHAR *pwszField, OPTIONAL IN OUT DWORD *pcwcObjectId, OPTIONAL OUT WCHAR *pwszObjectId, OPTIONAL OUT WCHAR const **ppwszObjectIdDescription) { ASNTABLE const *pasn; HRESULT hr = S_OK; BOOL fSaveCert = TRUE; BYTE const *pb = pbCert; long index; DWORD length; DWORD acbLevel[20]; DWORD iLevel; DWORD iLevelNext; WCHAR const *pwszfieldname; DWORD cbdiff; DWORD aiElement[20]; DWORD aiElement7f[2]; DWORD iElementLevel; DWORD State; BOOL fSetField = FALSE; BOOL fSetObjectId = FALSE; CERT_INFO *pCertInfo = NULL; DWORD cbCertInfo; CERT_NAME_INFO *pNameInfo = NULL; DWORD cbNameInfo; WCHAR *pwszObjId = NULL; State = CHECK7F_NONE; if (NULL != ppwszObjectIdDescription) { *ppwszObjectIdDescription = NULL; } #if DBG_CERTSRV if (!fVerbose && DbgIsSSActive(DBG_SS_CERTLIBI)) { fVerbose = TRUE; } #endif // DBG_CERTSRV if (fVerbose) { CONSOLEPRINT1((MAXDWORD, "myCheck7f: %x bytes\n", cbCert)); } pasn = asnCert; iLevel = 0; ZeroMemory(aiElement7f, sizeof(aiElement7f)); acbLevel[iLevel] = cbCert; iElementLevel = 0; while (0 != iLevel || (0 != acbLevel[iLevel] && NULL != pasn->pwszElement)) { DWORD i; if (1 < fVerbose) { if (2 < fVerbose) { CONSOLEPRINT3(( DBG_SS_CERTLIBI, "ASN:0: *pb=%x %u: %ws\n", *pb, pasn - asnCert, pasn->pwszElement)); } CONSOLEPRINT0((MAXDWORD, "LENGTHS:0:")); for (i = 0; i <= iLevel; i++) { CONSOLEPRINT1((MAXDWORD, " %3x", acbLevel[i])); } CONSOLEPRINT0((MAXDWORD, "\n")); } while (OPTIONAL_FIELD & pasn->Flags) { DWORD f; if (0 < acbLevel[iLevel] && MATCHTAG(*pb, pasn->Flags)) { #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIB, "Optional field MATCH cb=%x %ws\n", acbLevel[iLevel], pasn->pwszElement)); } #endif // DBG_CERTSRV break; } #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIB, "Optional field NO match cb=%x %ws\n", acbLevel[iLevel], pasn->pwszElement)); } #endif // DBG_CERTSRV f = 0; switch ((BEG_REPEAT1 | BEG_REPEAT2) & pasn->Flags) { case BEG_REPEAT1: f = END_REPEAT1; break; case BEG_REPEAT2: f = END_REPEAT2; break; } if (f) { while (!(f & pasn->Flags)) { #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIB, "Skipping[%x] %ws\n", f, pasn->pwszElement)); } #endif // DBG_CERTSRV pasn++; } } else { DWORD iLevelCurrent; GetLevel(pasn->pwszElement, &iLevelCurrent); while (TRUE) { GetLevel(pasn[1].pwszElement, &iLevelNext); if (iLevelNext <= iLevelCurrent) { break; } #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT1(( DBG_SS_CERTLIB, "Skipping nested optional field %ws\n", pasn->pwszElement)); } #endif // DBG_CERTSRV pasn++; } } #if DBG_CERTSRV if (fVerbose) { CONSOLEPRINT1(( DBG_SS_CERTLIB, "Skipping optional field %ws\n", pasn->pwszElement)); } #endif // DBG_CERTSRV pasn++; if (0 == acbLevel[iLevel]) { GetLevel(pasn->pwszElement, &iLevelNext); if (iLevelNext < iLevel) { iLevel = iLevelNext; } } } while ((END_REPEAT1 | END_REPEAT2) & pasn->Flags) { // Make sure only one END_REPEAT bit is on. assert( (END_REPEAT1 | END_REPEAT2) != ((END_REPEAT1 | END_REPEAT2) & pasn->Flags)); pwszfieldname = GetLevel(pasn->pwszElement, &iLevelNext); if (!RestoreLevel(acbLevel, iLevelNext, &iLevel, fVerbose)) { goto error; } i = (BYTE) pasn->Flags; assert((DWORD) (pasn - asnCert) > i); if (0 != acbLevel[iLevel]) { if (!MATCHTAG(*pb, (pasn - i)->Flags)) { CONSOLEPRINT5(( MAXDWORD, "Check7f: Unexpected tag at %x: at level %u: (%x/%x) %ws\n", cbCert - acbLevel[0], iLevel, *pb, pasn->Flags, pasn->pwszElement)); goto error; } // Some data remain at this level, and the type tag matches // the expected repeat tag, loop back to the start of the // section to be repeated. pasn -= i; // Make sure only one BEG_REPEAT bit is on. assert( (BEG_REPEAT1 | BEG_REPEAT2) != ((BEG_REPEAT1 | BEG_REPEAT2) & pasn->Flags)); // Make sure the BEG_REPEAT bit in the begin record matches // the END_REPEAT bit in the end record. assert( ((BEG_REPEAT1 & pasn->Flags) && (END_REPEAT1 & pasn[i].Flags)) || ((BEG_REPEAT2 & pasn->Flags) && (END_REPEAT2 & pasn[i].Flags))); } else { pasn++; iElementLevel--; } } if (2 < fVerbose) { CONSOLEPRINT3(( DBG_SS_CERTLIBI, "ASN:1: *pb=%x %u: %ws\n", *pb, pasn - asnCert, pasn->pwszElement)); } if ((BEG_REPEAT1 | BEG_REPEAT2) & pasn->Flags) { if ((BEG_REPEAT1 & pasn->Flags) && 0 == iElementLevel || (BEG_REPEAT2 & pasn->Flags) && 1 == iElementLevel) { iElementLevel++; aiElement[iElementLevel] = 0; } aiElement[iElementLevel]++; } pwszfieldname = GetLevel(pasn->pwszElement, &iLevelNext); if (!RestoreLevel(acbLevel, iLevelNext, &iLevel, fVerbose)) { goto error; } if (1 < fVerbose) { CONSOLEPRINT0((MAXDWORD, "LENGTHS:1:")); for (i = 0; i <= iLevel; i++) { CONSOLEPRINT1((MAXDWORD, " %3x", acbLevel[i])); } CONSOLEPRINT0((MAXDWORD, "\n")); } if (0 == iLevel && 0 == acbLevel[0]) { break; // all done! } if (!MATCHTAG(*pb, pasn->Flags)) { CONSOLEPRINT5(( MAXDWORD, "Check7f: Unexpected tag at %x: at level %u: (%x/%x) %ws\n", cbCert - acbLevel[0], iLevel, *pb, pasn->Flags, pasn->pwszElement)); goto error; } GetLevel(pasn[1].pwszElement, &iLevelNext); index = DecodeLength( fVerbose, &length, iLevel, pbCert, &pb[1], acbLevel[iLevel] - 1, pasn->pwszElement); if (fVerbose) { DWORD ccol; char achdbg[128]; char *pchdbg; //char achbuf[10]; pchdbg = achdbg; pchdbg += sprintf(pchdbg, "%04x:", pb - pbCert); for (i = 0; i <= iLevel; i++) { pchdbg += sprintf(pchdbg, " %3x", acbLevel[i]); } pchdbg += sprintf(pchdbg, " (%x)", length); ccol = SAFE_SUBTRACT_POINTERS(pchdbg, achdbg); if (ccol > 34) { ccol = 34; } pchdbg += sprintf(pchdbg, " %*hs -- ", 34 - ccol, ""); assert(2 >= iElementLevel); if (1 == iElementLevel) { pchdbg += sprintf(pchdbg, "[%u]:", aiElement[1] - 1); } else if (2 == iElementLevel) { pchdbg += sprintf( pchdbg, "[%u,%u]:", aiElement[1] - 1, aiElement[2] - 1); } CONSOLEPRINT2((DBG_SS_CERTLIBI, "%hs%ws\n", achdbg, pwszfieldname)); } if (length == cbOLDCERTENROLLCHOKESLENGTH) { CONSOLEPRINT2(( MAXDWORD, "Check7f: Length of %ws is %u bytes\n", pwszfieldname, length)); if (CHECK7F_NONE == State) { ReturnString(pwszfieldname, pcwcField, pwszField); if (1 <= iElementLevel) { aiElement7f[0] = aiElement[1]; } if (2 <= iElementLevel) { aiElement7f[1] = aiElement[2]; } State = pasn->State; fSetField = TRUE; } } if (1 < fVerbose) { CONSOLEPRINT6(( DBG_SS_CERTLIBI, "index=%x len=%x level=%x->%x acb[%x]=%x\n", index, length, iLevel, iLevelNext, iLevel, acbLevel[iLevel])); } if (0 > index || index + length > acbLevel[iLevel]) { CONSOLEPRINT2(( MAXDWORD, "Check7f: BAD LENGTH: i=%x l=%x\n", index, length)); goto error; } cbdiff = index + 1; if (iLevelNext > iLevel) { assert(iLevel + 1 == iLevelNext); } else { cbdiff += length; } for (i = 0; i <= iLevel; i++) { if (acbLevel[i] < cbdiff) { CONSOLEPRINT3(( MAXDWORD, "Check7f: BAD NESTED LENGTH[%u]: %x < %x\n", i, acbLevel[i], cbdiff)); goto error; } acbLevel[i] -= cbdiff; } if (iLevelNext > iLevel) { iLevel++; if (1 < fVerbose) { CONSOLEPRINT2(( DBG_SS_CERTLIBI, "Saving length(%u) <== %x\n", iLevel, length)); } acbLevel[iLevel] = length; } pb += cbdiff; pasn++; } *pIndex1 = 0; if (0 != iLevel || 0 != acbLevel[iLevel] || NULL != pasn->pwszElement) { CONSOLEPRINT3(( MAXDWORD, "Check7f: Mismatch: %x bytes left at: %x: %ws\n", acbLevel[iLevel], cbCert - acbLevel[0], pasn->pwszElement)); } else if (!fSetField) { fSaveCert = FALSE; } if (fSetField && NULL != pcwcObjectId) { char const *pszObjId; CERT_NAME_BLOB const *pNameBlob; // Decode certificate cbCertInfo = 0; if (!myDecodeObject( X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, pbCert, cbCert, CERTLIB_USE_LOCALALLOC, (VOID **) &pCertInfo, &cbCertInfo)) { hr = GetLastError(); goto error; } pszObjId = NULL; pNameBlob = NULL; switch (State) { case CHECK7F_ISSUER_RDN: case CHECK7F_ISSUER_RDN_ATTRIBUTE: case CHECK7F_ISSUER_RDN_STRING: pNameBlob = &pCertInfo->Issuer; break; case CHECK7F_SUBJECT_RDN: case CHECK7F_SUBJECT_RDN_ATTRIBUTE: case CHECK7F_SUBJECT_RDN_STRING: pNameBlob = &pCertInfo->Subject; break; case CHECK7F_EXTENSION: case CHECK7F_EXTENSION_VALUE: case CHECK7F_EXTENSION_VALUE_RAW: if (0 != aiElement7f[0] && aiElement7f[0] <= pCertInfo->cExtension) { pszObjId = pCertInfo->rgExtension[aiElement7f[0] - 1].pszObjId; } break; default: break; } if (NULL != pNameBlob) { if (!myDecodeName( X509_ASN_ENCODING, X509_UNICODE_NAME, pNameBlob->pbData, pNameBlob->cbData, CERTLIB_USE_LOCALALLOC, &pNameInfo, &cbNameInfo)) { hr = GetLastError(); goto error; } if (0 != aiElement7f[0] && aiElement7f[0] <= pNameInfo->cRDN) { CERT_RDN *pRDN; pRDN = &pNameInfo->rgRDN[aiElement7f[0] - 1]; if (0 != aiElement7f[1] && aiElement7f[1] <= pRDN->cRDNAttr) { pszObjId = pRDN->rgRDNAttr[aiElement7f[1] - 1].pszObjId; } } } if (NULL != pszObjId) { if (!ConvertSzToWsz(&pwszObjId, pszObjId, -1)) { hr = E_OUTOFMEMORY; goto error; } ReturnString(pwszObjId, pcwcObjectId, pwszObjectId); fSetObjectId = TRUE; if (NULL != ppwszObjectIdDescription) { WCHAR const *pwszDesc; pwszDesc = myGetOIDNameA(pszObjId); if (NULL != pwszDesc && L'\0' != *pwszDesc) { *ppwszObjectIdDescription = pwszDesc; } } } } error: if (fSaveCert) { EncodeToFileW( fSetField? L"c:\\7flen.crt" : L"c:\\7fasn.crt", pbCert, cbCert, DECF_FORCEOVERWRITE | CRYPT_STRING_BINARY); } if (NULL != pCertInfo) { LocalFree(pCertInfo); } if (NULL != pNameInfo) { LocalFree(pNameInfo); } if (NULL != pwszObjId) { LocalFree(pwszObjId); } *pState = State; if (NULL != pIndex1) { *pIndex1 = aiElement7f[0]; } if (NULL != pIndex2) { *pIndex2 = aiElement7f[1]; } if (!fSetField && NULL != pcwcField) { if (NULL != pwszField && 0 < *pcwcField) { pwszField[0] = L'\0'; } *pcwcField = 0; } if (!fSetObjectId && NULL != pcwcObjectId) { if (NULL != pwszObjectId && 0 < *pcwcObjectId) { pwszObjectId[0] = L'\0'; } *pcwcObjectId = 0; } if (fVerbose) { CONSOLEPRINT1((MAXDWORD, "myCheck7f: --> %x\n", hr)); } return(hr); }