(转)iOS 证书、密钥及信任服务

时间:2022-09-05 18:51:50

iOS 证书、密钥及信任服务

——翻译自Apple Reference《Certificate,Key,and Trust Services Programming Guide》

本章描述并演示了如何使用证书、密钥和信任服务去导入一个indentity,评估证书是否可信,判断证书失效的原因,以及失效证书的恢复。

本章按如下顺序分别演示了:

导入一个 identity.

从导入的数据中获得证书.

获得用于证书评估的策略.

校验证书,根据指定策略评估证书是否可信.

测试证书中的可恢复错误.

判断证书是否过期.

改变评估条件,忽略过期证书.

重新评估证书.

“ 第2章,Certificate,Key,and Trust Services Concepts”,介绍了证书,密钥和信任服务的概念和术语。关于证书,密钥和信任服务的细节内容,请参考Certificate,Key,and Trust Services Reference.

从一个.p12文件中提取、评估Identity

 

如果你需要在iOS设备上使用加密过的identity(一个密钥及其关联的证书)进行客户端认证,例如——你可以把PKCS#12数据以受密码保护的文件的方式安全地传输到这个设备上。本节显示如何从PKCS#12数据中提取identity和trust objects(可信任对象),并评估其可信度。

列表 2-1 显示了用SecPKCS12Import函数从.p12文件中提取identity和可信任对象,以及评估其可信度。

列表 2-2 显示如何从identity中获取证书并显示证书信息。每个列表后都对代码进行了解释。

在编译这段代码时,请确认在Xcode工程中加入了Security.framework。

列表   2-1  从PKCS#12数据中提取identity和trust对象

#import <UIKit/UIKit.h>

#import <Security/Security.h>

#import <CoreFoundation/CoreFoundation.h>

NSString *thePath = [[NSBundle mainBundle]

pathForResource:@"MyIdentity" ofType:@"p12"];

NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];

CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;             // 1

OSStatus status = noErr;

SecIdentityRef myIdentity;

SecTrustRef myTrust;

status = extractIdentityAndTrust(

inPKCS12Data,

&myIdentity,

&myTrust);                 // 2

if status != 0 ...  //Do some error checking here

SecTrustResultType trustResult;

if (status == noErr) {                                      // 3

status = SecTrustEvaluate(myTrust, &trustResult);

}

...                                                             // 4

if (trustResult == kSecTrustResultRecoverableTrustFailure) {

...;

}

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data,        // 5

SecIdentityRef *outIdentity,

SecTrustRef *outTrust)

{

OSStatus securityError = errSecSuccess;

CFStringRef password = CFSTR("Password");

const void *keys[] =   { kSecImportExportPassphrase };

const void *values[] = { password };

CFDictionaryRef optionsDictionary = CFDictionaryCreate(

NULL, keys,

values, 1,

NULL, NULL);  // 6

CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

securityError = SecPKCS12Import(inPKCS12Data,

optionsDictionary,

&items);                    // 7

//

if (securityError == 0) {                                   // 8

CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);

const void *tempIdentity = NULL;

tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,

kSecImportItemIdentity);

*outIdentity = (SecIdentityRef)tempIdentity;

const void *tempTrust = NULL;

tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);

*outTrust = (SecTrustRef)tempTrust;

}

if (optionsDictionary)

CFRelease(optionsDictionary);                            // 9

[PKCS12Data release];

在这段代码中 :

检索PKCS#12文件并获得数据。本例中,该文件位于application bundle中。你也可以通过网络方式把文件传输给你的应用程序。

调用该函数获得identity和trust对象(见步骤5)。

评估证书。这里的信任对象(trust object),包括信任策略和其他用于判断证书是否可信的信息,都已经含在了PKCS数据中。要单独评估一个证书是否可信,见列表 2-6。

处理信任结果。如果信任结果是kSecTrustResultInvalid,kSecTrustResultDeny,kSecTrustResultFatalTrustFailure,你无法进行处理。如果评估结果是kSecTrustResultRecoverableTrustFailure,你可以从信任失败中恢复。参见“从信任失败中恢复”。

第2步中调用的函数的具体实现。

构造包含了密码的dictionary,用于传递给SecPKCS12Import函数。注意这里使用的是core foundation中的CFDictionaryRef,与NSDictionary完全等价。列表 2-9 则是一个使用NSDictionary的例子。

从PKCS#12数据中提取证书、密钥和trust并将其放到数组中。

从数组中取出第1个dictionary,并从dictionary中取出identity和trust。SecPKCS12Import函数将PKCS数据中的每一个条目返回为一个dictionary。本例中,identity被提取到数组的第1个元素。

释放dictionary和PKCS12Data,他们不再被使用。

以下列表显示如何从identity中获取证书以及显示证书信息。编译本段代码前请确保在工程中导入了Security.framework。

列表   2-2  显示证书信息

// 从identity获取证书 .

SecCertificateRef myReturnedCertificate = NULL;

status = SecIdentityCopyCertificate (myReturnedIdentity,

&myReturnedCertificate);  // 1

CFStringRef certSummary = SecCertificateCopySubjectSummary

(myReturnedCertificate);  // 2

NSString* summaryString = [[NSString alloc]

initWithString:(NSString*)certSummary];  // 3

//Display the string

...

[summaryString release];                                   // 4

在这段代码中 :

从identity中提取证书。

从证书中获取summary摘要信息。

string 转换为NSString。

释放NSString。

获取和使用持久化的钥匙串

当你在钥匙串中添加或查找一个条目时,你需要有一个持久化的引用。因为持久化引用能保证在程序从启动到能写入磁盘这段时间内,始终可用。当需要反复在钥匙串中查找条目时,使用持久化引用更加容易。以下代码演示如何获取一个 identity 的持久化引用。

列表   2-3  获取identity的持久化引用

CFDataRef persistentRefForIdentity(SecIdentityRef identity)

{

OSStatus status;

CFTypeRef  identity_handle = NULL;

const void *keys[] =   { kSecReturnPersistentRef, kSecValueRef };

const void *values[] = { kCFBooleanTrue,          identity };

CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,

2, NULL, NULL);

status = SecItemAdd(dict, &persistent_ref);

if (dict)

CFRelease(dict);

return (CFDataRef)persistent_ref;

}

下面演示使用持久化引用从钥匙串中检索identity对象。

列表 2-4  用持久化引用获取identity对象

SecIdentityRef identityForPersistentRef(CFDataRef persistent_ref)

{

CFTypeRef   identity_ref     = NULL;

const void *keys[] =   { kSecReturnRef,  kSecValuePersistentRef };

const void *values[] = { kCFBooleanTrue, persistent_ref };

CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,

2, NULL, NULL);

SecItemCopyMatching(dict, &identity_ref);

if (dict)

CFRelease(dict);

return (SecIdentityRef)identity_ref;

}

 

从钥匙串中查找证书

以下代码演示如何使用证书名(在钥匙串中用证书名标识证书)查找证书。要用持久化引用在钥匙串中找到一个条目,参考列表 2-4。要用一个id字串查找一个条目,参考“数据加密和解密”。

列表 2-5  在钥匙串中查找证书

CFTypeRef   certificateRef     = NULL;                      // 1

const char *certLabelString = "Romeo Montegue";

CFStringRef certLabel = CFStringCreateWithCString(

NULL, certLabelString,

kCFStringEncodingUTF8);         // 2

const void *keys[] =   { kSecClass, kSecAttrLabel, kSecReturnRef };

const void *values[] = { kSecClassCertificate, certLabel, kCFBooleanTrue };

CFDictionaryRef dict = CFDictionaryCreate(NULL, keys,

values, 3,

NULL, NULL);       // 3

status = SecItemCopyMatching(dict, &certificateRef);        // 4

if (dict)

CFRelease(dict);

在这段代码中 :

定义变量,存储证书对象。

定义字符串,存储证书名。

定义 dictionary,存储证书查找条件。键-值序列中的键 kSecReturnRef表明,函数调用结束时应返回一个钥匙串条目的引用(当查找有结果时)。

在钥匙串中查找证书。

 

获取策略对象并评估可信度

评估证书可信度之前,必需获取到一个证书对象的引用。你可以从一个identity中提取一个证书对象(列表 2-2),也可以从DER证书数据中创建证书对象(使用SecCertificateCreateWithData函数,见列表 2-6),或者从钥匙串中查找证书(列表 2-5)。

评估信任度的标准由信任策略(trust policy)指定。列表 3-2 显示如何获得用于评估的策略对象。在iOS中有两种策略可用:Basic X509和SSL(参考AppleX509TP 信任策略)。可以用SecPolicyCreateBasicX509或者SecPolicyCreateSSL函数获取策略对象。

下列代码显示了获取策略对象并用于评估证书是否可信。

列表 2-6  获取策略对象用于评估

NSString *thePath = [[NSBundle mainBundle]

pathForResource:@"Romeo Montegue" ofType:@"cer"];

NSData *certData = [[NSData alloc]

initWithContentsOfFile:thePath];

CFDataRef myCertData = (CFDataRef)certData;                 // 1

SecCertificateRef myCert;

myCert = SecCertificateCreateWithData(NULL, myCertData);    // 2

SecPolicyRef myPolicy = SecPolicyCreateBasicX509();         // 3

SecCertificateRef certArray[1] = { myCert };

CFArrayRef myCerts = CFArrayCreate(

NULL, (void *)certArray,

1, NULL);

SecTrustRef myTrust;

OSStatus status = SecTrustCreateWithCertificates(

myCerts,

myPolicy,

&myTrust);  // 4

SecTrustResultType trustResult;

if (status == noErr) {

status = SecTrustEvaluate(myTrust, &trustResult);       // 5

}

...                                                             // 6

if (trustResult == kSecTrustResultRecoverableTrustFailure) {

...;

}

...

if (myPolicy)

CFRelease(myPolicy);                                    // 7

在这段代码中 :

查找证书文件并获取数据。本例中,该文件位于应用程序束。但你也可以从网络获取证书。如果证书存在于钥匙串中,参考“在钥匙串中查找证书”。

从证书数据中创建certificate引用。

创建用于评估证书的策略。

用证书和策略创建信任对象(trust)。如果存在中间证书或者锚证书,应把这些证书都包含在certificate数组中并传递给SecTrustCreateWithCertificates函数。这样会加快评估的速度。

评估一个信任对象。

处理信任结果(trust result)。如果信任结果是kSecTrustResultInvalid,kSecTrustResultDeny,kSecTrustResultFatalTrustFailure,你无法进行处理。如果信任结果是kSecTrustResultRecoverableTrustFailure,你可以恢复这个错误。参考“从信任失败中恢复”。

释放策略对象。

 

从信任失败中恢复

 

信任评估的结果有多个,这取决于:是否证书链中的所有证书都能找到并全都有效,以及用户对这些证书的信任设置是什么。信任结果怎么处理则由你的程序来决定。例如,如果信任结果是kSecTrustResultConfirm,你可以显示一个对话框,询问用户是否允许继续。

信任结果kSecTrustResultRecoverableTrustFailure的意思是:信任被否决,但可以通过改变设置获得不同结果。例如,如果证书签发过期,你可以改变评估日期以判断是否证书是有效的同时文档是已签名的。列表 3-4 演示如何改变评估日期。注意 CFDateCreate函数使用绝对时间(从2001年1月1日以来的秒数)。你可以用CFGregorianDateGetAbsoluteTime函数把日历时间转换为绝对时间。

列表 2-7  设置评估时间

SecTrustResultType trustResult;

status = SecTrustEvaluate(myTrust, &trustResult);       // 1

//Get time used to verify trust

CFAbsoluteTime trustTime,currentTime,timeIncrement,newTime;

CFDateRef newDate;

if (trustResult == kSecTrustResultRecoverableTrustFailure) {// 2

trustTime = SecTrustGetVerifyTime(myTrust);             // 3

timeIncrement = 31536000;                               // 4

currentTime = CFAbsoluteTimeGetCurrent();               // 5

newTime = currentTime - timeIncrement;                  // 6

if (trustTime - newTime){                                // 7

newDate = CFDateCreate(NULL, newTime);              // 8

SecTrustSetVerifyDate(myTrust, newDate);            // 9

status = SecTrustEvaluate(myTrust, &trustResult);   // 10

}

}

if (trustResult != kSecTrustResultProceed) {                // 11

...

}

在这段代码中:

评估证书可信度。参考“获取策略对象并评估可信度”。

检查信任评估结果是否是可恢复的失败( kSecTrustResultRecoverableTrustFailure )。

取得证书的评估时间(绝对时间)。如果证书在评估时已经过期了,则被认为无效。

设置时间的递增量为1年(以秒计算)。

取得当前时间的绝对时间。

设置新时间(第2次评估的时间)为当前时间减一年。

检查评估时间是否大于1年前(最近一次评估是否1年前进行的)。如果是,使用新时间(1年前的时间)进行评估,看证书是否在1年前就已经过期。

把新时间转换为CFDateRef。也可以用NSDate,二者是完全互通的,方法中的NSDate*参数,可以用CFDateRef进行传递;反之亦可。

设置信任评估时间为新时间(1年前)。

再次进行信任评估。如果证书是因为过期(到期时间在1年内)导致前次评估失败,那么这次评估应该成功。

再次检查评估结果。如果仍不成功,则需要做更进一步的操作,比如提示用户安装中间证书,或则友好地告知用户证书校验失败。

 

数据加密和解密

证书,密钥和信任API包含了生产不对称密钥对并用于数据加密/解密的函数集。例如,你可能想加密数据,这些数据的备份不能被访问。或者,你可能想在你的iOS应用和桌面应用间共享公钥/私钥对,以通过网络发送加密数据。列表 2-8 显示如何产生可用于手机的公/私钥对。列表 2-9 显示如何用公钥加密数据,列表 2-10 显示如何用私钥解密数据。注意,这几个示例都使用了cocoa对象(如NSMutableDictionary),而本章其他示例使用了core framework对象(如CFMutableDictionaryRef),二者是等价的。

列表 2-8  生成密钥对

static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey/0";

static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey/0";

// 1

- (void)generateKeyPairPlease

{

OSStatus status = noErr;

NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];

NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];

NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];

// 2

NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier

length:strlen((const char *)publicKeyIdentifier)];

NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier

length:strlen((const char *)privateKeyIdentifier)];

// 3

SecKeyRef publicKey = NULL;

SecKeyRef privateKey = NULL;                                 // 4

[keyPairAttr setObject:(id)kSecAttrKeyTypeRSA

forKey:(id)kSecAttrKeyType]; // 5

[keyPairAttr setObject:[NSNumber numberWithInt:1024]

forKey:(id)kSecAttrKeySizeInBits]; // 6

[privateKeyAttr setObject:[NSNumber numberWithBool:YES]

forKey:(id)kSecAttrIsPermanent]; // 7

[privateKeyAttr setObject:privateTag

forKey:(id)kSecAttrApplicationTag]; // 8

[publicKeyAttr setObject:[NSNumber numberWithBool:YES]

forKey:(id)kSecAttrIsPermanent]; // 9

[publicKeyAttr setObject:publicTag

forKey:(id)kSecAttrApplicationTag]; // 10

[keyPairAttr setObject:privateKeyAttr

forKey:(id)kSecPrivateKeyAttrs]; // 11

[keyPairAttr setObject:publicKeyAttr

forKey:(id)kSecPublicKeyAttrs]; // 12

status = SecKeyGeneratePair((CFDictionaryRef)keyPairAttr,

&publicKey, &privateKey); // 13

//    error handling...

if(privateKeyAttr) [privateKeyAttr release];

if(publicKeyAttr) [publicKeyAttr release];

if(keyPairAttr) [keyPairAttr release];

if(publicKey) CFRelease(publicKey);

if(privateKey) CFRelease(privateKey);                       // 14

}

在这段代码中 :

定义公/私钥id的字符串变量,以便后面使用。

定义dictionary,用于传递SecKeyGeneratePair函数中的第1个参数。

把第1步中定义的字符串转换为NSData对象。

为公/私钥对准备SecKeyRef对象。

设置密钥对的密钥类型为RSA。

设置密钥对的密钥长度为1024。

设置私钥的持久化属性(即是否存入钥匙串)为YES。

把1-3步中的identifier放到私钥的dictionary中。

设置公钥的持久化属性(即是否存入钥匙串)为YES。

把1-3步中的identifier放到公钥的dictionary中。

把私钥的属性集(dictionary)加到密钥对的属性集(dictionary)中。

把公钥的属性集(dictionary)加到密钥对的属性集(dictionary)中。

产生密钥对。

释放无用对象。

你可以把公钥发送给任何人,他们可以用它来加密数据。假设你安全地保存了私钥,则只有你能解密这些数据。以下代码演示如何用公钥加密数据。可以用从设备上产生的公钥(见后面代码),或者从证书中提取的公钥(发送给你的证书或者已经在钥匙串中的证书)。用SecTrustCopyPublicKey函数可以从证书中提取公钥。下面假设这个密钥由设备产生并已放到钥匙串中。

列表 2-9  用公钥加密数据

- (void)encryptWithPublicKey

{

OSStatus status = noErr;

size_t cipherBufferSize;

uint8_t *cipherBuffer;                     // 1

// [cipherBufferSize]

const uint8_t nonce[] = "the quick brown fox jumps

over the lazy dog/0"; // 2

SecKeyRef publicKey = NULL;                                 // 3

NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier

length:strlen((const char *)publicKeyIdentifier)]; // 4

NSMutableDictionary *queryPublicKey =

[[NSMutableDictionary alloc] init]; // 5

[queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];

[queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];

[queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];

[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];

// 6

status = SecItemCopyMatching

((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7

//  Allocate a buffer

cipherBufferSize = cipherBufferSize(publicKey);

cipherBuffer = malloc(cipherBufferSize);

//  Error handling

if (cipherBufferSize < sizeof(nonce)) {

// Ordinarily, you would split the data up into blocks

// equal to cipherBufferSize, with the last block being

// shorter. For simplicity, this example assumes that

// the data is short enough to fit.

printf("Could not decrypt.  Packet too large./n");

return;

}

// Encrypt using the public.

status = SecKeyEncrypt(    publicKey,

kSecPaddingPKCS1,

nonce,

(size_t) sizeof(nonce)/sizeof(nonce[0]),

cipherBuffer,

&cipherBufferSize

);                               // 8

//  Error handling

//  Store or transmit the encrypted text

if(publicKey) CFRelease(publicKey);

if(queryPublicKey) [queryPublicKey release];                // 9

free(cipherBuffer);

}

在这段代码中 :

定义缓存,用于放入加密文本。

指定要加密的文本。

定义SecKeyRef,用于公钥。

定义NSData对象,存储公钥的identifier(见列表 2-8 的第1、3、8步),该id在钥匙串中唯一。

定义dictionary,用于从钥匙串中查找公钥。

设置dictionary的键-值属性。属性中指定,钥匙串条目类型为“密钥”,条目identifier为第4步中指定的字符串,密钥类型为RSA,函数调用结束返回查找到的条目引用。

调用SecItemCopyMatching函数进行查找。

加密数据, 返回结果用PKCS1格式对齐。

释放不用的变量。

The following code sample shows how to decrypt data. This sample uses the private key corresponding to the public key used to encrypt the data, and assumes you already have the cipher text created in the preceding example. It gets the private key from the keychain using the same technique as used in the preceding example to get the public key.

下面代码演示如何解密。本例采用与加密数据的公钥对的私钥进行解密,并且密文为上面例子中的加密结果。从钥匙串中获取私钥,采用与上例相同的技术。

列表 2-10  用私钥解密

- (void)decryptWithPrivateKey

{

OSStatus status = noErr;

size_t plainBufferSize;;

uint8_t *plainBuffer;

SecKeyRef privateKey = NULL;

NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier

length:strlen((const char *)privateKeyIdentifier)];

NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];

// Set the private key query dictionary.

[queryPrivateKey setObject:(id)kSecClassKey forKey:(id)kSecClass];

[queryPrivateKey setObject:privateTag forKey:(id)kSecAttrApplicationTag];

[queryPrivateKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];

[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];

// 1

status = SecItemCopyMatching

((CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2

if (plainBufferSize < cipherBufferSize) {

// Ordinarily, you would split the data up into blocks

// equal to plainBufferSize, with the last block being

// shorter. For simplicity, this example assumes that

// the data is short enough to fit.

printf("Could not decrypt.  Packet too large./n");

return;

}

//  Allocate the buffer

plainBufferSize = SecKeyGetBlockSize(privateKey);

plainBuffer = malloc(plainBufferSize)

//  Error handling

status = SecKeyDecrypt(    privateKey,

kSecPaddingPKCS1,

cipherBuffer,

cipherBufferSize,

plainBuffer,

&plainBufferSize

);                              // 3

//  Error handling

//  Store or display the decrypted text

if(publicKey) CFRelease(publicKey);

if(privateKey) CFRelease(privateKey);

if(queryPublicKey) [queryPublicKey release];

if(queryPrivateKey) [queryPrivateKey release];              // 4

}

在这段代码中 :

准备dictionary,用于从钥匙串查找私钥。

在钥匙串中找到私钥。

解密数据。

释放无用的变量。

(转)iOS 证书、密钥及信任服务的更多相关文章

  1. iOS服务器证书不受信任的解决版本

    参考文章链接: https://www.cnblogs.com/v-jing/p/6008964.html http://www.cocoachina.com/ios/20151021/13722.h ...

  2. IOS证书/私钥/代码签名/描述文件

    1.   相关资源 (1)   钥匙串程序(常用工具->钥匙串),用于创建证书请求.安装证书.导出私钥等 (2)   IOS开发中心:https://developer.apple.com/de ...

  3. iOS 证书申请和使用详解(详细版)

    对于iOS开发者来说,apple开发者账号肯定不会陌生.在开发中我们离不开它.下面我简单的为大家分享一下关于iOS开发中所用的证书相关知识. 第一部分:成员介绍 1.Certification(证书) ...

  4. iOS 证书与签名 解惑详解

    iOS 证书与签名 解惑详解 分类: iPhone2012-06-06 19:57 9426人阅读 评论(1) 收藏 举报 iosxcodecryptographyappleiphone测试   目录 ...

  5. Nginx集群之SSL证书的WebApi微服务

    目录 1       大概思路... 1 2       Nginx集群之SSL证书的WebApi微服务... 1 3       HTTP与HTTPS(SSL协议)... 1 4       Ope ...

  6. iOS证书申请及使用详细说明

    iOS 证书申请和使用详解(详细版)阅读   对于iOS开发者来说,apple开发者账号肯定不会陌生.在开发中我们离不开它.下面我简单的为大家分享一下关于iOS开发中所用的证书相关知识. 第一部分:成 ...

  7. iOS 证书申请和使用详解(详细版)阅读

    对于iOS开发者来说,apple开发者账号肯定不会陌生.在开发中我们离不开它.下面我简单的为大家分享一下关于iOS开发中所用的证书相关知识. 第一部分:成员介绍 1.Certification(证书) ...

  8. https本地自签名证书添加到信任证书访问

    1.背景 本文适用于基于https(http+ssl)的网站通信.本地调试等,上线是请寻找免费 ssl证书申请. 本地调试过程中,一些特殊的场景需要我使用http+ssl通信,比如在Chrome中使用 ...

  9. iOS证书失效

    iOS证书突然失效 今早上班打包直接报错,错误如图 根据错误信息到“钥匙串”里面看了一下证书,证书都莫名其妙的失效了,昨天还是好好的. 重新去钥匙串从证颁发中心获取证书,然后登陆开发者账号重新申请证书 ...

随机推荐

  1. sql查询指定范围内的所有月份

    ),) FROM master..spt_values WHERE type='P' AND DATEADD(MONTH,number,'2016-01-01')<='2017-01-01'

  2. Java基础の乱弹琴二:break关键字

    Java中的break一般用于 跳出一个switch或者循环. 跳出switch基本不用赘述. break跳出循环一般是跳出当前一层循环. 如若需要跳出多层循环可以在break后加标签,然后把标签标注 ...

  3. 【android】TabLayout文字闪烁问题

    安卓MD设计提供了一个非常酷炫的效果,TabLayout拿来做选项卡时非常合适的,但是在实际使用中发现22.2.1版本号的TabLayout在ViewPager滑动的时候会出现闪烁现象. 解决方法:在 ...

  4. &lt&semi;meta name&equals;&quot&semi;viewport&quot&semi; content&equals;&quot&semi;width&equals;device-width&comma; initial-scale&equals;1&period;0&comma; user-scalable&equals;0&comma; minimum-scale&equals;1&period;0&comma; maximum-scale&equals;1&period;0&quot&semi; &sol;&gt&semi;

    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalabl ...

  5. XML数组和对象,反之亦然

    惊人的互相转换,还是因为麻烦.程序很反感麻烦猿 1 阵转xml <?php /* 一维数组转xml 思路: 循环数组每一个单元,添加到xml文档节点中去 */ /* $arr = array( ...

  6. Eclipse Oxygen 解决 自动导包的问题

    换成了 Eclipse 的Oxygen 版本 , 发现之前好用的自动导包功能不能用了 (Ctrl+Shift+O) 再 网上看资料  上面说 将  In Windows 替换为Editing Java ...

  7. 使用superMap实现点标注和区域着色

    1.定义html文件,引入superMap的js和theme文件: <script src='${_ctxPath }/statics/js/superMap/SuperMap.Include. ...

  8. 3&period;3 for 循环

    Python 编程中 for循环用来遍历序列类型的对象,逐一取出序列中的元素值,每取出一个元素值就执行一次循环体,直到元素取完,循环结束.循环体中的代码块可以和序列中的元素值一点关系都没有,因为for ...

  9. NSL:CPK&lowbar;NN神经网络实现预测哪个样本与哪个样本处在同一层,从而科学规避我国煤矿突水灾难—Jason niu

    load water_data.mat attributes = mapminmax(attributes); P_train = attributes(:,1:35); T_train = clas ...

  10. 关于Struts2的jsp页面的注释

    语句就算用<!-- -->注释后,还是会在编译的时候显示在网页上,而且网页还会报错,因为注释的那些语句也会去编译,也会去检查有没有错误,所以一些注释掉的过时的变量和方法也会导致报错.500