Обнаружение CA: TRUE в x509 Basic Contraints - PullRequest
1 голос
/ 07 февраля 2012

Как правильно проверить основные ограничения сертификата? Ниже приведен код, который я сейчас использую для имитации значков, отображаемых в цепочке для ключей (причина ниже в том, что пока у нас есть

 SFChooseIdentityPanel * identityPanel = [SFChooseIdentityPanel sharedChooseIdentityPanel];

эквивалент для выбора CA или сертификата Host / Leaf не существует. И это полезно при настройке / блокировке соединений SSL.

К сожалению - я не могу найти строки OID в заголовочных файлах для чистого извлечения CA: TRUE или ложного формирования сертификата (или неправильно использую API).

Так что вопросы

  • Как правильно проверить CA: TRUE - пока работает следующее - я могу себе представить, что он будет сорван неправильным сертификатом с текстовыми строками в нужных местах.

  • Во-вторых, я использую эвристику Эмитента == Подлежит обнаружению самоподписанного. Есть ли более чистый способ сделать это?

  • Наконец - методом проб и ошибок - ниже, кажется, подражает Apple ее выбор в цепочке для ключей - но документы довольно трудно понять. Действительно ли kSecTrustResultProceed означает, что пользователь установил переопределение и kSecTrustResultUnspecified, что на самом деле доверие определяется базовым доверием системы? Хотя это и работает, я не совсем понимаю точную интерпретацию документов.

Большое спасибо. Код ниже.

Dw.

@implementation NSImage (CertificateSelectionPanelExtensions)

+(NSImage *)iconForCertificate:(SecCertificateRef)certificateRef small:(BOOL)isSmall
{
    BOOL isCA = FALSE, isInvalid = TRUE, isUserTrust = FALSE;

    NSString * issuer = nil, * subject = nil;

    const void *keys[] = { kSecOIDX509V1SubjectName, kSecOIDX509V1IssuerName, kSecOIDExtendedKeyUsage, kSecOIDBasicConstraints };
    CFArrayRef keySelection = CFArrayCreate(NULL, keys , sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks);
    CFDictionaryRef vals = SecCertificateCopyValues(certificateRef, keySelection, NULL);

    CFArrayRef values;
    CFDictionaryRef dict;

    dict = CFDictionaryGetValue(vals, kSecOIDBasicConstraints );
    values = dict ? CFDictionaryGetValue(dict, kSecPropertyKeyValue) : NULL;
    if (values) {
        for(int i = 0; i < CFArrayGetCount(values); i++) {
            CFDictionaryRef subDict = CFArrayGetValueAtIndex(values, i);

            // We cannot find OID defines for the CA - so rely on the lower libraries to give us a string
            // of sorts. Not a good idea - as now this code can be foiled by a actual string.
            //
            NSString *k = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(subDict, kSecPropertyKeyLabel)];
            NSString *v = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(subDict, kSecPropertyKeyValue)];
            if ([@"Certificate Authority" isEqualToString:k] && [@"Yes" isEqualToString:v]) {
                isCA = TRUE;
            }
        }
    };

    // Fall back on a simple self-sign check if there where no kSecOIDBasicConstraints.
    // set on the cert. Note that it is a DN is equal check - in some cases
    // doing a 509v3 Subject/Authority Key Identifier may be better ?? XXXX
    //
    if (!isCA && !values) {
        dict = CFDictionaryGetValue(vals, kSecOIDX509V1SubjectName);
        values = dict ? CFDictionaryGetValue(dict, kSecPropertyKeyValue) : NULL;
        subject = [NSString stringWithFormat:@"%@", values];

        dict = CFDictionaryGetValue(vals, kSecOIDX509V1IssuerName);
        values = dict ? CFDictionaryGetValue(dict, kSecPropertyKeyValue) : NULL;
        issuer = [NSString stringWithFormat:@"%@", values];

        // Crap way of secondgessing CA ness.
        if ([issuer isEqualToString:subject])
            isCA = TRUE;
    };

    SecPolicyRef policy = SecPolicyCreateBasicX509(); // SecPolicyCreateSSL(YES,nil);
    CFArrayRef chain = CFArrayCreate(NULL, (const void**)(&certificateRef), 1, NULL);

    SecTrustRef trustRef;    
    SecTrustCreateWithCertificates(chain, policy, &trustRef);

    SecTrustResultType result;
    SecTrustEvaluate (trustRef, &result);

    if(result == kSecTrustResultProceed) {
        isUserTrust = TRUE;
        isInvalid = FALSE;
    } else
    if (result == kSecTrustResultUnspecified)
        isInvalid = FALSE;

    CFRelease(trustRef);
    CFRelease(chain);

    // Images as per /System/Library/Frameworks/SecurityInterface.framework/Versions/A/Resources
    // Cert <Small | Large> <Personal | Root> [_Invalid | _UserTrust ]
    //
    return [NSImage imageNamed:[NSString stringWithFormat:@"Cert%@%@%@",
                                isSmall ? @"Small" : @"Large",
                                isCA ? @"Root" : @"Personal",
                                isInvalid ? @"_Invalid" : (isUserTrust ? @"_UserTrust" : @"")]];
}
@end

1 Ответ

2 голосов
/ 07 февраля 2012

Расширение basicConstraints определяется в X.509 следующим образом:

basicConstraints EXTENSION ::= {
    SYNTAX BasicConstraintsSyntax
    IDENTIFIED BY id-ce-basicConstraints }
BasicConstraintsSyntax ::= SEQUENCE {
    cA BOOLEAN DEFAULT FALSE, 
    pathLenConstraint INTEGER (0..MAX) OPTIONAL }

Это, в свою очередь, кодируется в соответствии с правилами выдающегося кодирования ( X.690 ). Отдельные части последовательности BasicConstraintsSyntax не имеют своих собственных OID.

Я бы не стал претендовать на звание эксперта, но я не думаю, что есть проблема с тестом для флага cA, который вы делаете. Я не думаю, что [NSString stringWithFormat:@"%@", ...] часть необходима, ум.

Что касается проверки самоподписанных сертификатов, то, по-видимому, необоснованно проверять имена субъекта и эмитента; очевидно, это действительно говорит вам, действительно ли сертификат утверждает, что является самоподписанным, и для проверки того, что это действительно так, вам нужно проверить подпись самостоятельно (независимо от того, хотите ли вы этого, я не знаю). К сведению, по теме идентификаторов ключей, согласно RFC3280 , в конкретном случае самозаверяющего сертификата идентификатор ключа авторизации может быть опущен, поэтому сертификат без идентификатора ключа авторизации может быть указание на то, что сертификат был самозаверяющим, но кто-то вполне может намеренно выдать искаженный сертификат без идентификатора ключа доступа.

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

Еще одна вещь, о которой стоит сказать, это то, что есть код, который может помочь с такими вещами; например, библиотека MYCrypto Дженса Альфке

Редактировать (8 февраля 2012 г.)

В соответствии с X.509 Style Guide возможно, что имя subject будет пустым, в этом случае вам нужно будет взглянуть на subjectAltName расширение вместо. Маловероятно, что это нарушит тест для самозаверяющих сертификатов, основанных на сравнении имен субъекта и эмитента - кажется неразумным выдавать себе сертификат, предоставляя DN для имени эмитента, но оставляя имя субъекта пустым. Однако стоит иметь в виду.

...