internal _SqlMetaDataSet(int count, SqlTceCipherInfoTable? cipherTable) { cekTable = cipherTable; metaDataArray = new _SqlMetaData[count]; for(int i = 0; i < metaDataArray.Length; ++i) { metaDataArray[i] = new _SqlMetaData(i); } }
/// <summary> /// Writes a single entry of CEK Table into TDS Stream (for bulk copy). /// </summary> /// <returns></returns> internal void WriteEncryptionEntries (ref SqlTceCipherInfoTable cekTable, TdsParserStateObject stateObj) { for (int i =0; i < cekTable.Size; i++) { // Write Db ID WriteInt(cekTable[i].DatabaseId, stateObj); // Write Key ID WriteInt(cekTable[i].CekId, stateObj); // Write Key Version WriteInt(cekTable[i].CekVersion, stateObj); // Write 8 bytes of key MD Version Debug.Assert (8 == cekTable[i].CekMdVersion.Length); stateObj.WriteByteArray (cekTable[i].CekMdVersion, 8, 0); // We don't really need to send the keys stateObj.WriteByte(0x00); } }
/// <summary> /// <para> Parses the TDS message to read a single CIPHER_INFO table.</para> /// </summary> internal bool TryProcessCipherInfoTable (TdsParserStateObject stateObj, out SqlTceCipherInfoTable? cipherTable) { // Read count short tableSize = 0; cipherTable = null; if (!stateObj.TryReadInt16(out tableSize)) { return false; } if (0 != tableSize) { SqlTceCipherInfoTable tempTable = new SqlTceCipherInfoTable(tableSize); // Read individual entries for (int i = 0; i < tableSize; i++) { SqlTceCipherInfoEntry entry; if (!TryReadCipherInfoEntry (stateObj, out entry)) { return false; } tempTable[i] = entry; } cipherTable = tempTable; } return true; }
private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col, SqlTceCipherInfoTable? cipherTable, bool fColMD, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { byte byteLen; UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (IsYukonOrNewer) { if (!stateObj.TryReadUInt32(out userType)) { return false; } } else { ushort userTypeShort; if (!stateObj.TryReadUInt16(out userTypeShort)) { return false; } userType = userTypeShort; } // read flags and set appropriate flags in structure byte flags; if (!stateObj.TryReadByte(out flags)) { return false; } col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2); col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable)); col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity)); // read second byte of column metadata flags if (!stateObj.TryReadByte(out flags)) { return false; } col.isColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet)); if (fColMD && _serverSupportsColumnEncryption) { col.isEncrypted = (TdsEnums.IsEncrypted == (flags & TdsEnums.IsEncrypted)); } // Read TypeInfo if (!TryProcessTypeInfo (stateObj, col, userType)) { return false; } // Read tablename if present if (col.metaType.IsLong && !col.metaType.IsPlp) { if (_isYukon) { int unusedLen = 0xFFFF; //We ignore this value if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName)) { return false; } } else { ushort shortLen; if (!stateObj.TryReadUInt16(out shortLen)) { return false; } string tableName; if (!stateObj.TryReadString(shortLen, out tableName)) { return false; } // with Sql2000 this is returned as an unquoted mix of catalog.owner.table // all of which may contain "." and unable to parse correctly from the string alone // example "select * from pubs..[A.B.C.D.E]" AND only when * will contain a image/text/ntext column // by delay parsing from execute to SqlDataReader.GetSchemaTable to enable more scenarios col.multiPartTableName = new MultiPartTableName(tableName); } } // Read the TCE column cryptoinfo if (fColMD && _serverSupportsColumnEncryption && col.isEncrypted) { // If the column is encrypted, we should have a valid cipherTable if (cipherTable.HasValue && !TryProcessTceCryptoMetadata (stateObj, col, cipherTable.Value, columnEncryptionSetting, isReturnValue: false)) { return false; } } // Read the column name if (!stateObj.TryReadByte(out byteLen)) { return false; } if (!stateObj.TryReadString(byteLen, out col.column)) { return false; } // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings. // We only need to fire this event when we actually have a meta data stream with 0 or more rows. stateObj._receivedColMetaData = true; return true; }
internal bool TryProcessTceCryptoMetadata (TdsParserStateObject stateObj, SqlMetaDataPriv col, SqlTceCipherInfoTable? cipherTable, SqlCommandColumnEncryptionSetting columnEncryptionSetting, bool isReturnValue) { Debug.Assert(isReturnValue == (cipherTable == null), "Ciphertable is not set iff this is a return value"); // Read the ordinal into cipher table ushort index = 0; UInt32 userType; // For return values there is not cipher table and no ordinal. if (cipherTable.HasValue) { if (!stateObj.TryReadUInt16(out index)) { return false; } // validate the index (ordinal passed) if (index >= cipherTable.Value.Size) { Bid.Trace("<sc.TdsParser.TryProcessTceCryptoMetadata|TCE> Incorrect ordinal received %d, max tab size: %d\n", index, cipherTable.Value.Size); throw SQL.ParsingErrorValue(ParsingErrorState.TceInvalidOrdinalIntoCipherInfoTable, index); } } // Read the user type if (!stateObj.TryReadUInt32(out userType)) { return false; } // Read the base TypeInfo col.baseTI = new SqlMetaDataPriv(); if (!TryProcessTypeInfo(stateObj, col.baseTI, userType)) { return false; } // Read the cipher algorithm Id byte cipherAlgorithmId; if (!stateObj.TryReadByte(out cipherAlgorithmId)) { return false; } string cipherAlgorithmName = null; if (TdsEnums.CustomCipherAlgorithmId == cipherAlgorithmId) { // Custom encryption algorithm, read the name byte nameSize; if (!stateObj.TryReadByte(out nameSize)) { return false; } if (!stateObj.TryReadString(nameSize, out cipherAlgorithmName)) { return false; } } // Read Encryption Type. byte encryptionType; if (!stateObj.TryReadByte(out encryptionType)) { return false; } // Read Normalization Rule Version. byte normalizationRuleVersion; if (!stateObj.TryReadByte(out normalizationRuleVersion)) { return false; } Debug.Assert(col.cipherMD == null, "col.cipherMD should be null in TryProcessTceCryptoMetadata."); // Check if TCE is enable and if it is set the crypto MD for the column. // TCE is enabled if the command is set to enabled or to resultset only and this is not a return value // or if it is set to use connection setting and the connection has TCE enabled. if ((columnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled || (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.ResultSetOnly && !isReturnValue)) || (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _connHandler != null && _connHandler.ConnectionOptions != null && _connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled)) { col.cipherMD = new SqlCipherMetadata(cipherTable.HasValue ? (SqlTceCipherInfoEntry?)cipherTable.Value[index] : null, index, cipherAlgorithmId: cipherAlgorithmId, cipherAlgorithmName: cipherAlgorithmName, encryptionType: encryptionType, normalizationRuleVersion: normalizationRuleVersion); } else { // If TCE is disabled mark the MD as not encrypted. col.isEncrypted = false; } return true; }