Я пытаюсь написать код на C #, который позволит мне отправлять запросы на сервер Chef.Следуя документации для API сервера chef , я пытаюсь подписать канонический заголовок в своем коде C #, чтобы я мог проходить проверку подлинности на сервере и делать запросы.
Я обнаружил следующеескрипт в документах шеф-повара (см. «cURL»), который работает с моим клиентским сертификатом.Вызов этого скрипта возвращает ожидаемый ответ JSON с сервера.Часть сценария, которая используется для подписи канонического заголовка:
method="GET"
hashed_path=$(echo -n "/organizations/[org]/nodes" | openssl dgst -sha1 -binary | openssl enc -base64) #where [org] is my organization
hashed_body=$(echo -n "" | openssl dgst -sha1 -binary | openssl enc -base64)
timestamp=$(date -u "+%Y-%m-%dT%H:%M:%SZ")
canonical_request="Method:$method\nHashed Path:$hashed_path\nX-Ops-Content-Hash:$hashed_body\nX-Ops-Timestamp:$timestamp\nX-Ops-UserId:$client_name"
auth_headers=$(printf "$canonical_request" | openssl rsautl -sign -inkey \
"$(_chef_dir)/${client_name}.pem" | openssl enc -base64 | _chomp | awk '{ll=int(length/60);i=0; \
while (i<=ll) {printf " -H X-Ops-Authorization-%s:%s", i+1, substr($0,i*60+1,60);i=i+1}}')
Важной частью приведенного выше фрагмента является $(printf "$canonical_request" | openssl rsautl -sign -inkey "$(_chef_dir)/${client_name}.pem" | openssl enc -base64
.
У меня есть некоторый код на C #адаптированный из dotnet-chef-api на GitHub , который я пытаюсь заставить делать то же самое.Он использует криптографические библиотеки BouncyCastle для подписи содержимого.
private string Sign(string privateKey)
{
var method = _method.ToString().ToUpperInvariant(); //evals to 'GET'
var hashedPath = _requestUri.AbsolutePath.ToBase64EncodedSha1String(); //evals to hash of '/organizations/[org]/nodes'
var contentHash = _body.ToBase64EncodedSha1String(); //evals to hash of empty string
var canonicalHeader = $"Method:{method}\nHashed Path:{hashedPath}\nX-Ops-Content-Hash:{contentHash}\nX-Ops-Timestamp:{_timestamp}\nX-Ops-UserId:{_client}";
var input = Encoding.UTF8.GetBytes(canonicalHeader);
using (var stringReader = new StringReader(privateKey))
{
var pemReader = new PemReader(stringReader);
var key = ((AsymmetricCipherKeyPair) pemReader.ReadObject()).Private;
var signer = new RsaDigestSigner(new NullDigest());
signer.Init(true, key);
signer.BlockUpdate(input, 0, input.Length);
return Convert.ToBase64String(signer.GenerateSignature());
}
}
Я проверил с помощью отладчика и множества операторов echo
, что канонический заголовок в моем bash-скрипте точнотакой же, как канонический заголовок в моем коде C #.Тем не менее, я полностью застрял на подписи.Код, который я извлек из проекта GitHub, не изменился, но он генерирует строку Base64, отличную от той, которую я получаю из сценария bash (с удаленными временными метками).
Как мне что-то подписать в C # втак же, как он подписан с помощью инструмента openssl?Я попытался переключить NullDigest для других типов, но не нашел тот, который дает тот же результат Base64, что и двоичные файлы openssl.Я также открыт для лучших способов сделать это, если они уже существуют в рамках .Net Framework.