Поделиться через


Конфиденциальный реестр Azure записывает квитанции о транзакциях

Для обеспечения целостности транзакций конфиденциальный реестр Azure использует структуру данных дерева Merkle для записи хэша всех блоков транзакций, добавленных в неизменяемый реестр. После фиксации транзакции записи пользователи конфиденциального реестра Azure могут получить криптографическое подтверждение Merkle или квитанцию по записи, созданной в конфиденциальном реестре, чтобы убедиться, что операция записи была правильно сохранена. Получение транзакции записи является подтверждением того, что система зафиксировала соответствующую транзакцию и может использоваться для проверки того, что запись была эффективно добавлена в реестр.

Дополнительные сведения о том, как дерево Merkle используется в конфиденциальном реестре, можно найти в документации по CCF.

Получение квитанций о транзакциях записи

Настройка и необходимые компоненты

Пользователи конфиденциального реестра Azure могут получить квитанцию для определенной транзакции с помощью клиентской библиотеки конфиденциального реестра Azure. В следующем примере показано, как получить получение квитанции записи с помощью клиентской библиотеки для Python, но эти действия совпадают с любым другим поддерживаемым пакетом SDK для Конфиденциального реестра Azure.

Предполагается, что ресурс конфиденциального реестра уже создан с помощью библиотеки управления конфиденциальными реестрами Azure. Если у вас еще нет существующего ресурса реестра, создайте его с помощью следующих инструкций.

Пошаговое руководство по написанию кода

Начнем с настройки импорта для программы Python.

import json 

# Import the Azure authentication library 
from azure.identity import DefaultAzureCredential 

# Import the Confidential Ledger Data Plane SDK 
from azure.confidentialledger import ConfidentialLedgerClient 
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient 

Ниже приведены постоянные значения, используемые для настройки клиента конфиденциального реестра Azure. Обязательно обновите константу ledger_name с уникальным именем ресурса конфиденциального реестра.

# Constants for our program 
ledger_name = "<your-unique-ledger-name>" 
identity_url = "https://identity.confidential-ledger.core.azure.com" 
ledger_url = "https://" + ledger_name + ".confidential-ledger.azure.com" 

Мы проверяем подлинность с помощью класса DefaultAzureCredential.

# Setup authentication 
credential = DefaultAzureCredential() 

Затем мы получаем и сохраняем сертификат службы конфиденциального реестра с помощью клиента сертификата из URL-адреса удостоверения конфиденциального реестра. Сертификат службы — это сертификат открытого ключа сети, используемый как корневой каталог доверия для проверки подлинности сервера TLS . Другими словами, он используется в качестве центра сертификации (ЦС) для установления соединения TLS с любым из узлов в сети CCF.

# Create a Certificate client and use it to 
# get the service identity for our ledger 
identity_client = ConfidentialLedgerCertificateClient(identity_url) 
network_identity = identity_client.get_ledger_identity( 
     ledger_id=ledger_name 
)

# Save network certificate into a file for later use 
ledger_tls_cert_file_name = "network_certificate.pem" 

with open(ledger_tls_cert_file_name, "w") as cert_file: 
    cert_file.write(network_identity["ledgerTlsCertificate"]) 

Затем мы можем использовать наши учетные данные, извлекаемый сетевой сертификат и уникальный URL-адрес реестра для создания клиента конфиденциального реестра.

# Create Confidential Ledger client 
ledger_client = ConfidentialLedgerClient( 
     endpoint=ledger_url,  
     credential=credential, 
     ledger_certificate_path=ledger_tls_cert_file_name 
) 

С помощью клиента конфиденциального реестра можно выполнять любые поддерживаемые операции в экземпляре конфиденциального реестра Azure. Например, можно добавить новую запись в реестр и ожидать фиксации соответствующей транзакции записи.

# The method begin_create_ledger_entry returns a poller that  
# we can use to wait for the transaction to be committed 
create_entry_poller = ledger_client.begin_create_ledger_entry( 
    {"contents": "Hello World!"} 
)

create_entry_result = create_entry_poller.result() 

После фиксации транзакции клиент может получить квитанцию по записи, добавленной в реестр на предыдущем шаге, используя соответствующий идентификатор транзакции.

# The method begin_get_receipt returns a poller that  
# we can use to wait for the receipt to be available by the system 
get_receipt_poller = ledger_client.begin_get_receipt( 
    create_entry_result["transactionId"] 
)

get_receipt_result = get_receipt_poller.result() 

Пример кода

Предоставляется полный пример кода, используемый в пошаговом руководстве по коду.

import json 

# Import the Azure authentication library 
from azure.identity import DefaultAzureCredential 

# Import the Confidential Ledger Data Plane SDK 
from azure.confidentialledger import ConfidentialLedgerClient 
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient 

from receipt_verification import verify_receipt 

# Constants 
ledger_name = "<your-unique-ledger-name>" 
identity_url = "https://identity.confidential-ledger.core.azure.com" 
ledger_url = "https://" + ledger_name + ".confidential-ledger.azure.com" 

# Setup authentication 
credential = DefaultAzureCredential() 

# Create Ledger Certificate client and use it to 
# retrieve the service identity for our ledger 
identity_client = ConfidentialLedgerCertificateClient(identity_url) 
network_identity = identity_client.get_ledger_identity(ledger_id=ledger_name) 

# Save network certificate into a file for later use 
ledger_tls_cert_file_name = "network_certificate.pem" 

with open(ledger_tls_cert_file_name, "w") as cert_file: 
    cert_file.write(network_identity["ledgerTlsCertificate"]) 

# Create Confidential Ledger client 
ledger_client = ConfidentialLedgerClient( 
    endpoint=ledger_url, 
    credential=credential, 
    ledger_certificate_path=ledger_tls_cert_file_name, 
) 

# The method begin_create_ledger_entry returns a poller that 
# we can use to wait for the transaction to be committed 
create_entry_poller = ledger_client.begin_create_ledger_entry( 
    {"contents": "Hello World!"} 
) 
create_entry_result = create_entry_poller.result() 

# The method begin_get_receipt returns a poller that 
# we can use to wait for the receipt to be available by the system 
get_receipt_poller = ledger_client.begin_get_receipt( 
    create_entry_result["transactionId"] 
) 
get_receipt_result = get_receipt_poller.result() 

# Save fetched receipt into a file
with open("receipt.json", "w") as receipt_file: 
    receipt_file.write(json.dumps(get_receipt_result, sort_keys=True, indent=2)) 

Запись содержимого квитанции о транзакциях

Ниже приведен пример полезных данных ответа JSON, возвращаемых экземпляром конфиденциального реестра Azure при вызове конечной GET_RECEIPT точки.

{
    "receipt": {
        "cert": "-----BEGIN CERTIFICATE-----\nMIIB0jCCAXmgAwIBAgIQPxdrEtGY+SggPHETin1XNzAKBggqhkjOPQQDAjAWMRQw\nEgYDVQQDDAtDQ0YgTmV0d29yazAeFw0yMjA3MjAxMzUzMDFaFw0yMjEwMTgxMzUz\nMDBaMBMxETAPBgNVBAMMCENDRiBOb2RlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\nQgAEWy81dFeEZ79gVJnfHiPKjZ54fZvDcFlntFwJN8Wf6RZa3PaV5EzwAKHNfojj\noXT4xNkJjURBN7q+1iE/vvc+rqOBqzCBqDAJBgNVHRMEAjAAMB0GA1UdDgQWBBQS\nwl7Hx2VkkznJNkVZUbZy+TOR/jAfBgNVHSMEGDAWgBTrz538MGI/SdV8k8EiJl5z\nfl3mBTBbBgNVHREEVDBShwQK8EBegjNhcGljY2lvbmUtdGVzdC1sZWRnZXIuY29u\nZmlkZW50aWFsLWxlZGdlci5henVyZS5jb22CFWFwaWNjaW9uZS10ZXN0LWxlZGdl\ncjAKBggqhkjOPQQDAgNHADBEAiAsGawDcYcH/KzF2iK9Ldx/yABUoYSNti2Cyxum\n9RRNKAIgPB/XGh/FQS3nmZLExgBVXkDYdghQu/NCY/hHjQ9AvWg=\n-----END CERTIFICATE-----\n",
        "leafComponents": {
            "claimsDigest": "0000000000000000000000000000000000000000000000000000000000000000",
            "commitEvidence": "ce:2.40:f36ffe2930ec95d50ebaaec26e2bec56835abd051019eb270f538ab0744712a4",
            "writeSetDigest": "8452624d10bdd79c408c0f062a1917aa96711ea062c508c745469636ae1460be"
        },
        "nodeId": "70e995887e3e6b73c80bc44f9fbb6e66b9f644acaddbc9c0483cfc17d77af24f",
        "proof": [
            {
                "left": "b78230f9abb27b9b803a9cae4e4cec647a3be1000fc2241038867792d59d4bc1"
            },
            {
                "left": "a2835d4505b8b6b25a0c06a9c8e96a5204533ceac1edf2b3e0e4dece78fbaf35"
            }
        ],
        "signature": "MEUCIQCjtMqk7wOtUTgqlHlCfWRqAco+38roVdUcRv7a1G6pBwIgWKpCSdBmhzgEdwguUW/Cj/Z5bAOA8YHSoLe8KzrlqK8="
    },
    "state": "Ready",
    "transactionId": "2.40"
}

Ответ JSON содержит следующие поля на корневом уровне.

  • получение: содержит значения, которые можно использовать для проверки действительности квитанции для соответствующей транзакции записи.

  • состояние: состояние возвращаемого ответа JSON. Ниже приведены возможные значения:

    • Ready: получение, возвращенное в ответе, доступно
    • Loading: получение квитанции пока недоступно, и запрос должен быть извлечен
  • transactionId: идентификатор транзакции, связанный с получением транзакции записи.

Поле receipt содержит следующие поля.

  • Сертификат: строка с сертификатом открытого ключа PEM узла CCF, подписав транзакцию записи. Сертификат удостоверения службы всегда должен поддерживать сертификат узла подписывания. Дополнительные сведения о том, как транзакции регулярно подписываются и как транзакции подписи добавляются в реестр в CCF по следующей ссылке.

  • nodeId: шестнадцатеричная строка, представляющая хэш-хэш SHA-256 открытого ключа узла CCF подписывания.

  • leafComponents: компоненты хэша конечного узла в дереве Merkle, связанном с указанной транзакцией. Дерево Merkle — это структура данных дерева, которая записывает хэш каждой транзакции и гарантирует целостность реестра. Дополнительные сведения о том, как используется дерево Merkle в CCF, см. в соответствующей документации по CCF.

  • доказательство. Список пар "ключ-значение", представляющих хэши дерева Merkle, которые при сочетании с хэшом конечного узла, соответствующего данной транзакции, позволяют повторно выполнять компиляцию корневого хэша дерева. Благодаря свойствам дерева Merkle можно перекомпилировать корневой хэш дерева только подмножество узлов. Элементы в этом списке находятся в виде пар "ключ-значение": ключи указывают относительную позицию относительно родительского узла в дереве на определенном уровне; значения — хэш-дайджесты SHA-256 данного узла, как шестнадцатеричные строки.

  • serviceEndorsements: список строк сертификатов в кодировке PEM, представляющих предыдущие сертификаты удостоверений службы. Возможно, удостоверение службы, одобренное узлом подписывания, не совпадает с идентификатором, выданным квитанцией. Например, сертификат службы обновляется после аварийного восстановления конфиденциального реестра. Список прошлых сертификатов службы позволяет аудиторам создавать цепочку доверия из узла подписи CCF к текущему сертификату службы.

  • сигнатура: строка Base64, представляющая сигнатуру корневого дерева Merkle в данной транзакции, путем подписывания узла CCF.

Поле leafComponents содержит следующие поля.

  • claimsDigest: шестнадцатеричная строка, представляющая хэш-дайджест SHA-256 утверждения приложения, присоединенного приложением Конфиденциального реестра во время выполнения транзакции. Утверждения приложения в настоящее время неподдерживаются, так как приложение конфиденциального реестра не присоединяет никаких утверждений при выполнении транзакции записи.

  • commitEvidence: уникальная строка, созданная для каждой транзакции, производная от идентификатора транзакции и секретов реестра. Дополнительные сведения о фиксации доказательств см. в соответствующей документации по CCF.

  • writeSetDigest: шестнадцатеричная строка, представляющая хэш-дайджест SHA-256 хранилища Key-Value, который содержит все ключи и значения, записанные во время завершения транзакции. Дополнительные сведения о наборе записи см. в соответствующей документации по CCF.

Утверждения приложения

Приложения конфиденциального реестра Azure могут присоединять произвольные данные, называемые утверждениями приложения, для записи транзакций. Эти утверждения представляют действия, выполняемые во время операции записи. При присоединении к транзакции дайджест SHA-256 объекта утверждений включается в реестр и фиксируется в рамках транзакции записи. Включение утверждения в транзакцию записи гарантирует, что дайджест утверждения подписан на месте и не может быть изменен.

Позже утверждения приложения можно выявить в их обычном формате в полезных данных квитанции, соответствующих той же транзакции, где они были добавлены. Предоставленные утверждения позволяют пользователям перекомпилировать тот же дайджест утверждений, который был присоединен и подписан реестром во время транзакции. Дайджест утверждений можно использовать в рамках процесса проверки получения транзакций записи, предоставляя автономный способ для пользователей, чтобы полностью проверить подлинность записанных утверждений.

Утверждения приложений в настоящее время поддерживаются в предварительной версии 2023-01-18-previewAPI.

Запись содержимого квитанции о транзакциях с помощью утверждений приложения

Ниже приведен пример полезных данных ответа JSON, возвращаемых экземпляром конфиденциального реестра Azure, который записывал утверждения приложения при вызове конечной GET_RECEIPT точки.

{
  "applicationClaims": [
    {
      "kind": "LedgerEntry",
      "ledgerEntry": {
        "collectionId": "subledger:0",
        "contents": "Hello world",
        "protocol": "LedgerEntryV1",
        "secretKey": "Jde/VvaIfyrjQ/B19P+UJCBwmcrgN7sERStoyHnYO0M="
      }
    }
  ],
  "receipt": {
    "cert": "-----BEGIN CERTIFICATE-----\nMIIBxTCCAUygAwIBAgIRAMR89lUNeIghDUfpyHi3QzIwCgYIKoZIzj0EAwMwFjEU\nMBIGA1UEAwwLQ0NGIE5ldHdvcmswHhcNMjMwNDI1MTgxNDE5WhcNMjMwNzI0MTgx\nNDE4WjATMREwDwYDVQQDDAhDQ0YgTm9kZTB2MBAGByqGSM49AgEGBSuBBAAiA2IA\nBB1DiBUBr9/qapmvAIPm1o3o3LRViSOkfFVI4oPrw3SodLlousHrLz+HIe+BqHoj\n4nBjt0KAS2C0Av6Q+Xg5Po6GCu99GQSoSfajGqmjy3j3bwjsGJi5wHh1pNbPmMm/\nTqNhMF8wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUCPaDohOGjVgQ2Lb8Pmubg7Y5\nDJAwHwYDVR0jBBgwFoAU25KejcEmXDNnKvSLUwW/CQZIVq4wDwYDVR0RBAgwBocE\nfwAAATAKBggqhkjOPQQDAwNnADBkAjA8Ci9myzieoLoIy+7mUswVEjUG3wrEXtxA\nDRmt2PK9bTDo2m3aJ4nCQJtCWQRUlN0CMCMOsXL4NnfsSxaG5CwAVkDwLBUPv7Zy\nLfSh2oZ3Wn4FTxL0UfnJeFOz/CkDUtJI1A==\n-----END CERTIFICATE-----\n",
    "leafComponents": {
      "claimsDigest": "d08d8764437d09b2d4d07d52293cddaf40f44a3ea2176a0528819a80002df9f6",
      "commitEvidence": "ce:2.13:850a25da46643fa41392750b6ca03c7c7d117c27ae14e3322873de6322aa7cd3",
      "writeSetDigest": "6637eddb8741ab54cc8a44725be67fd9be390e605f0537e5a278703860ace035"
    },
    "nodeId": "0db9a22e9301d1167a2a81596fa234642ad24bc742451a415b8d653af056795c",
    "proof": [
      {
        "left": "bcce25aa51854bd15257cfb0c81edc568a5a5fa3b81e7106c125649db93ff599"
      },
      {
        "left": "cc82daa27e76b7525a1f37ed7379bb80f6aab99f2b36e2e06c750dd9393cd51b"
      },
      {
        "left": "c53a15cbcc97e30ce748c0f44516ac3440e3e9cc19db0852f3aa3a3d5554dfae"
      }
    ],
    "signature": "MGYCMQClZXVAFn+vflIIikwMz64YZGoH71DKnfMr3LXkQ0lhljSsvDrmtmi/oWwOsqy28PsCMQCMe4n9aXXK4R+vY0SIfRWSCCfaADD6teclFCkVNK4317ep+5ENM/5T/vDJf3V4IvI="
  },
  "state": "Ready",
  "transactionId": "2.13"
}

По сравнению с примером получения, показанным в предыдущем разделе, ответ JSON содержит другое applicationClaims поле, представляющее список утверждений приложения, записанных реестром во время операции записи. Каждый объект внутри applicationClaims списка содержит следующие поля.

  • тип: представляет тип утверждения приложения. Значение указывает, как проанализировать объект утверждения приложения для указанного типа.

  • реестрEntry: представляет утверждение приложения, полученное из данных записи реестра. Утверждение будет содержать данные, записанные приложением во время транзакции записи (например, идентификатор коллекции и содержимое, предоставленное пользователем) и необходимые сведения для вычисления дайджеста, соответствующего одному объекту утверждения.

  • дайджест: он представляет утверждение приложения в дайджест-форме. Этот объект утверждения будет содержать предварительно вычисляемый дайджест приложения и протокол, используемый для вычисления.

Поле ledgerEntry содержит следующие поля.

  • протокол: он представляет протокол, используемый для вычисления дайджеста утверждения из заданных данных утверждения.

  • collectionId: идентификатор коллекции, записанной во время соответствующей транзакции записи.

  • содержимое: содержимое реестра, записанное во время соответствующей транзакции записи.

  • secretKey: ключ секрета в кодировке Base64. Этот ключ должен использоваться в алгоритме HMAC со значениями, указанными в утверждении приложения для получения дайджеста утверждений.

Поле digest содержит следующие поля.

  • протокол: он представляет протокол, используемый для вычисления дайджеста заданного утверждения.

  • значение: дайджест утверждения приложения в шестнадцатеричной форме. Это значение должно быть хэшировано protocol со значением для вычисления полного дайджеста утверждения приложения.

Дополнительные ресурсы

Дополнительные сведения о записи квитанций о транзакциях и о том, как CCF обеспечивает целостность каждой транзакции, см. в следующих ссылках:

Следующие шаги