在x509基本约束中检测CA:TRUE

时间:2012-02-07 12:36:05

标签: ios macos cocoa security x509

检查证书基本限制的正确方法是什么?下面是我目前用于模仿钥匙串中显示的图标的代码(下面的原因是我们有一个

 SFChooseIdentityPanel * identityPanel = [SFChooseIdentityPanel sharedChooseIdentityPanel];

选择CA或Host / Leaf证书的等效项不存在。这在设置/锁定SSL连接时非常有用。

不幸的是 - 我无法在头文件中找到OID字符串以干净地提取CA:TRUE或false形成证书(或者以错误的方式使用API​​)。

所以问题是

  • 如何干净地检查CA:TRUE - 在下面工作时 - 我可以想象它会被一个格式错误的证书挫败,文本字符串位于正确的位置。

  • 其次 - 我正在使用Issuer == Subject的启发式检测自签名。有更清洁的方法吗?

  • 最后 - 从试验和错误 - 下面似乎模仿苹果她在钥匙串中的选择 - 但文档很难理解。 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 个答案:

答案 0 :(得分:2)

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:@"%@", ...]部分是必要的,记住。

对于自签名证书的检查,测试主题和发行人名称似乎并不合理;显然,这真的告诉你证书声明是否是自签名的,并且实际测试你是否需要自己检查签名(这是否是你想要做的事情,我不是'知道)。 FYI,关于密钥标识符的主题,根据RFC3280,在自签名证书的特定情况下,可以省略授权密钥标识符,因此没有授权密钥标识符的证书可能表示证书是自签名的,但是完全可能有人故意发出没有权限密钥标识符的格式错误的证书。

最后一个问题似乎是通过查看文档来澄清的,这些文档表明这些值大致意味着你所说的。

另一件值得一提的是,那里有代码可以帮助解决这类问题;例如,Jens Alfke的MYCrypto

编辑(2012年2月8日)

根据X.509 Style Guide主题名称可能为空,在这种情况下,您需要查看 subjectAltName 扩展名。这不太可能会破坏依赖于比较主题和发行者名称的自签名证书的测试 - 向您自己发放证书为发行者名称提供DN但是然后将主题名称留空似乎是不合理的。但是,值得记住。