Swift (Linux): извлечение сертификатов CMS/PKCS#7 и проверка подписи контейнера?

Я пишу набор сервисов в Swift 4, которые будут работать на Linux. Одна из вещей, которые мне нужно сделать, это получить полезную нагрузку, которая подписана цифровой подписью с использованием формата синтаксиса криптографических сообщений (CMS), извлечь сертификат, используемый для его подписания, а затем проверить подпись. Я знаю, что Swift в Linux не содержит фреймворка безопасности или CommonCrypto для такого рода вещей, поэтому я связался с OpenSSL, чтобы попытаться помочь с этим. I'm about 2 years removed from my C / C++ Программирование дней, поэтому я с готовностью признаю, что я в этой части кода.

у меня есть 2 простых класса, чтобы действовать как обертки для OpenSSL BIO и PKCS7 структуры данных. Они выглядят так:

import Foundation
import OpenSSL

public final class BIOWrapper {

    public var bio = BIO_new(BIO_s_mem())

    public init(data: Data) {
        data.withUnsafeBytes { pointer -> Void in
            BIO_write(self.bio, pointer, Int32(data.count))
        }
    }

    public init() {}

    deinit {
        BIO_free(self.bio)
    }
}

public final class PKCS7Wrapper {

    public var pkcs7: UnsafeMutablePointer<PKCS7>

    public init(pkcs7: UnsafeMutablePointer<PKCS7>) {
        self.pkcs7 = pkcs7
    }

    deinit {
        PKCS7_free(self.pkcs7)
    }
}

Я могу успешно извлечь данные контейнера PKCS#7 и проверить, что значение кода типа данных NID_pkcs7_signed используя этот код:

let reqData = Data(bytes: reqBytes)
        guard reqData.count > 0 else {
            print("Empty request body")
            return nil
        }

        let bioWrapper = BIOWrapper(data: reqData)
        guard let container = d2i_PKCS7_bio(bioWrapper.bio, nil) else {
            print("No container")
            return nil
        }

        let pkcs7Wrapper = PKCS7Wrapper(pkcs7: container)
        let dataTypeCode = OBJ_obj2nid((pkcs7Wrapper.pkcs7.pointee.d.sign).pointee.contents.pointee.type)
        print("dataTypeCode : (dataTypeCode)")

        if dataTypeCode == NID_pkcs7_data {
            print("GOT DATA!")
        } else {
            print("Didn't get data")
            return nil
        }

       let pkcs7SignedTypeCode = OBJ_obj2nid(pkcs7Wrapper.pkcs7.pointee.type)
        if let signed = pkcs7SignedTypeCode == NID_pkcs7_signed {
            print("Signed : (signed)")
        }

тем не менее, я достиг точки, где я застрял. Как я могу получить данные сертификата X. 509 от полезная нагрузка PKCS#7? Я вижу, что pkcs7Wrapper.pkcs7.pointee.d.sign.pointee.cert структура данных должна содержать данные цепочки сертификатов. Его тип данных UnsafeMutablePointer<stack_st_x509> и я думаю, что могу выяснить код для использования OpenSSL PKCS7_verify метод, как только я получаю данные сертификата X. 509 в памяти. Я просто не знаю, как это сделать.

нашел на этом ресурсе это говорит о проверке квитанций на OSX/iOS, которая затрагивает многие из тех же вопросов. Они получают сертификат X. 509 из файловой системы и передайте данные в PKCS7_verify метод. Мне просто нужно знать, как получить данные сертификата из контейнера PKCS#7 для передачи.

может кто-нибудь помочь мне с этим? Я признаю, что вызов C из Swift не идеален, но в отсутствие хорошей структуры безопасности/криптографии для Swift я не знаю никаких других вариантов.

1 ответов


основная часть ответа находится в коде, который вы связали:

let store = X509_STORE_new()
X509_STORE_add_cert(store, appleRootX509)
OpenSSL_add_all_digests()
let result = PKCS7_verify(receiptPKCS7, nil, store, nil, nil, 0)
if result != 1 {
    log.atLevelDebug(id: 0, source: "Main", message: "Receipt signature verification failed")
    exit(errorCode)
}

Кажется, вам не хватает того факта, что вам не нужно самостоятельно извлекать сертификат X509 из данных PKCS7. The PKCS7_verify функция сделает это в рамках проверки:

предпринята попытка найти все сертификаты подписавшего, сначала посмотрев в параметре certs (если он не равен NULL), а затем посмотрев в любых сертификатах, содержащихся в p7 сама структура. Если не удается найти сертификаты подписавшего, операция завершается неудачно.

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

Если вам все еще нужно быстрое решение для извлечения сертификата из данных PKCS7 по какой-то причине, вам придется создать ASN.1 анализатор для pkcs7 в. Не уверен, что это легко доступно для Свифта,этот простой код что быстрый поиск дал, и этой хорошее описание данных PKCS7.