internal static bool UpdateCertificatesTableInternal(UpdateStep step) { var schema = ClusterStateMachine.CertificatesSchema; var readCertsTable = step.ReadTx.OpenTable(schema, ClusterStateMachine.CertificatesSlice); var writeCertsTable = step.WriteTx.OpenTable(schema, ClusterStateMachine.CertificatesSlice); using (var context = JsonOperationContext.ShortTermSingleUse()) { foreach (var cert in readCertsTable.SeekByPrimaryKey(Slices.Empty, 0)) { (string key, BlittableJsonReaderObject doc) = GetCurrentItem(step.WriteTx, context, cert); using (doc) { var def = JsonDeserializationServer.CertificateDefinition(doc); From11.DropCertificatePrefixFromDefinition(def, out var touched); var loweredKey = key.ToLowerInvariant(); if (loweredKey != key) { // we have upper cased key (thumbprint) // let's remove current record from table and force writing it again with lower cased key value using (Slice.From(step.WriteTx.Allocator, key, out Slice keySlice)) writeCertsTable.DeleteByKey(keySlice); touched = true; } if (touched) { using (Slice.From(step.WriteTx.Allocator, def.PublicKeyPinningHash, out Slice hashSlice)) using (Slice.From(step.WriteTx.Allocator, loweredKey, out Slice keySlice)) using (var newCert = context.ReadObject(def.ToJson(), "certificate/updated")) { ClusterStateMachine.UpdateCertificate(writeCertsTable, keySlice, hashSlice, newCert); } } } } } return(true); }
public bool Update(UpdateStep step) { ItemsSchema.Create(step.WriteTx, Items, 32); var itemsTable = step.WriteTx.OpenTable(ItemsSchema, Items); CertificatesSchema.Create(step.WriteTx, CertificatesSlice, 32); var certsTable = step.WriteTx.OpenTable(CertificatesSchema, CertificatesSlice); using (var context = JsonOperationContext.ShortTermSingleUse()) { // First we'll update all the certs in the local state with the pinning hash var localCertKeys = GetCertificateKeysFromLocalState(step.ReadTx).ToList(); foreach (var localCertKey in localCertKeys) { using (var localCertificate = GetLocalStateByThumbprint(step.ReadTx, context, localCertKey)) { if (localCertificate == null) { continue; } using (localCertificate) { var def = JsonDeserializationServer.CertificateDefinition(localCertificate); def.PublicKeyPinningHash = new X509Certificate2(Convert.FromBase64String(def.Certificate)).GetPublicKeyPinningHash(); using (var cert = context.ReadObject(def.ToJson(), "updated/certificate")) PutLocalState(step.WriteTx, localCertKey, cert); } } } // Read all the certs from the items table, add the pinning hash and store them in the new table. Then delete the original. var allClusterCerts = ItemsStartingWith(step.WriteTx, context, step.WriteTx.Allocator, Constants.Certificates.Prefix, 0, int.MaxValue).ToList(); foreach (var cert in allClusterCerts) { using (cert.Value) { var def = JsonDeserializationServer.CertificateDefinition(cert.Value); def.PublicKeyPinningHash = new X509Certificate2(Convert.FromBase64String(def.Certificate)).GetPublicKeyPinningHash(); using (Slice.From(step.WriteTx.Allocator, def.PublicKeyPinningHash, out Slice hashSlice)) using (Slice.From(step.WriteTx.Allocator, cert.ItemName, out Slice oldKeySlice)) // includes the 'certificates/' prefix using (Slice.From(step.WriteTx.Allocator, def.Thumbprint.ToLowerInvariant(), out Slice newKeySlice)) { // in this update we trim 'certificates/' prefix from key name, CollectionPrimaryKey and CollectionSecondaryKeys DropCertificatePrefixFromDefinition(def, out _); using (var newCert = context.ReadObject(def.ToJson(), "certificate/new/schema")) { ClusterStateMachine.UpdateCertificate(certsTable, newKeySlice, hashSlice, newCert); itemsTable.DeleteByKey(oldKeySlice); } } } } } return(true); }