如何在C#中创建PKCS12 .p12文件?

时间:2010-01-11 01:03:42

标签: c# security cryptography rsa x509certificate

这可能是一个n00b问题,但我在这方面没有任何经验。

我需要创建一个包含X509证书和私钥的p12包。我目前有两个对象,X509Certificate2和包含关键信息的RSAParameters对象。如何将这些组合成p12文件?

我找不到任何有关此事的信息。

我还有一个RSACryptoServiceProvider对象,如果有帮助的话,它会将RSAParameters中的参数导入其中。

一些额外的背景。我从我们在这里安装的VeriSign注册机构获得了我的证书。这是通过创建PCKS#10证书请求来完成的。我通过读入RA放入数据库的数据的字节数组来创建我的证书对象。

RsaPrivateCrtKeyParameters KeyParams = (RsaPrivateCrtKeyParameters)this.KeyPair.Private;
RSAParameters rsaParameters = new RSAParameters();

rsaParameters.Modulus = KeyParams.Modulus.ToByteArrayUnsigned();
rsaParameters.P = KeyParams.P.ToByteArrayUnsigned();
rsaParameters.Q = KeyParams.Q.ToByteArrayUnsigned();
rsaParameters.DP = KeyParams.DP.ToByteArrayUnsigned();
rsaParameters.DQ = KeyParams.DQ.ToByteArrayUnsigned();
rsaParameters.InverseQ = KeyParams.QInv.ToByteArrayUnsigned();
rsaParameters.D = KeyParams.Exponent.ToByteArrayUnsigned();
rsaParameters.Exponent = KeyParams.PublicExponent.ToByteArrayUnsigned();

RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
rsaKey.ImportParameters(rsaParameters);

this.Certificate.PrivateKey = rsaKey;

byte[] p12 = this.Certificate.Export(X509ContentType.Pkcs12, "password");

File.WriteAllBytes(fileName, p12);

PKCS10代(使用bouncycastle库)

509Name name = new X509Name(String.Concat(SubjectCommonName, "=", firstName, " ", lastName));
RsaKeyPairGenerator rkpg = new RsaKeyPairGenerator();
rkpg.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
this.KeyPair = rkpg.GenerateKeyPair();

// PKCS #10 Certificate Signing Request
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA1WITHRSA", name, this.KeyPair.Public, null, this.KeyPair.Private);
byte[] request = Base64.Encode(csr.GetEncoded());
ASCIIEncoding encoder  = new ASCIIEncoding();
return encoder.GetString(request);

证书请求(减去http帖子标题)。 public_key参数是base64编码的,pkcs10格式的CSR。 (我在每个参数之后都放了换行符,所以这里更容易阅读,它们不在实际的http帖子中)

operation=AutoAuthOSUserSubmit&
form_file=..%2ffdf%2fclient%2fuserEnrollMS.fdf&
authenticate=NO&
public_key_format=pkcs10&
country=NZ&
mail_firstName=Daniel&
mail_lastName=Mapletoft&
mail_email=daniel.mapletoft@nz.firstms.com&
challenge=1234&
public_key=MIIBTzCBuwIBADAUMRIwEAYDVQQDDAlTaW1vbiBEb2UwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANZD8M7gjUq1vBWq4w25x3SNhet4T+uCV3ebnAB5ws9f2YQevd9QeSfoPWw/pyJ/mJRDZDLjYzG63VQUzrXyBx3PZhmWqWaDECAYSssOYTfTMWPns0sRsyg1f35f4mh0ZXieiPYdv8r9CVjG9woa15LA1cYI0b93alM/z+OoMLxNAgMBAAEwCwYJKoZIhvcNAQEFA4GBAIB9buu5sycjdAgyV+UMAlzYKlENrQmI2/36ZZ4q3sx5bIyLm9tOEexbNzkk86kcGQhL2w/0oA5UpUCUU4IIf9u+lhpMoUlbHKH4tosswMwVEiFpfIWrL4M9X7+TW4Lj1aGf2T+xgKhWeo+cBSGexxvHo27OaH9d1NVDozEJ6c7i

这是Certificate.GetRawCertDataString()

的输出
3082036F30820257A003020102021034914BB0AF5A48704B56C89DE8B1BBFD300D06092A864886F70D0101050500304D310B3009060355040613024E5A31283026060355040A131F4669727374204D6F727467616765205365727669636573204C696D69746564311430120603550403130B464D5320526F6F74204341301E170D3130303132313030303030305A170D3131303132313233353935395A305B31243022060355040A141B4669727374204D6F727467616765205365727669636573204C7464311F301D060355040B1416466F72205465737420507572706F736573204F6E6C79311230100603550403140953696D6F6E20446F6530819F300D06092A864886F70D010101050003818D0030818902818100D643F0CEE08D4AB5BC15AAE30DB9C7748D85EB784FEB8257779B9C0079C2CF5FD9841EBDDF507927E83D6C3FA7227F9894436432E36331BADD5414CEB5F2071DCF661996A966831020184ACB0E6137D33163E7B34B11B328357F7E5FE2687465789E88F61DBFCAFD0958C6F70A1AD792C0D5C608D1BF776A533FCFE3A830BC4D0203010001A381C03081BD30090603551D1304023000300E0603551D0F0101FF0404030205A030600603551D1F0101FF045630543052A050A04E864C687474703A2F2F6F6E7369746563726C2E766572697369676E2E636F6D2F46697273744D6F72746761676553657276696365734C746450726F70656C6C632F4C617465737443524C2E63726C301F0603551D230418301680148B2A2C583903B2619F16E73D3DF1704DB1F3D4E2301D0603551D0E0416041411A6D5EBC14D7C226502EC340F70237D23431D0B300D06092A864886F70D010105050003820101008EFD93EF777F2D196FC8633C5A8347CA886320E59AF8AF8D3AA901AEF0ADF75EDD2D3C4495CF70F1E4516AA224F3731B6EE66DCB332FD88C03255DA9D12202DD3DF619EE55443F53773FD03C808B5B66AEEB39A3E20B866DC22D92010785A2729C269E35ED6B2036014628850B8E8A40A501F3C7EECA49A4B7E957B496ECD8A27702D7230C40580F94C69E83A0AEFD9347625B529E3ACDD2A5FEB7B946BEE9BE9DA9AA52E14AEC790C66E8A670AA1D53518DEFB66FE6BC33A57BB6A59C75C6DFADE5E961A9A03C3FFDC559FC9ADD565D345975B99BEF5F973D331E60A3FEFEF713C6C630D80222AD9541BC12F1E92379EF5CBECE81CA5E327FD32FDC28AB52D7

这是数组的内容     byte [] array1 = certKey.ExportCspBlob(false);

6,2,0,0,0,164,0,0,82,83,65,49,0,4,0,0,1,0,1,0,77,188,48,168,227,207,63,83,106,119,191,209,8,198,213,192,146,215,26,10,247,198,88,9,253,202,191,29,246,136,158,120,101,116,104,226,95,126,127,53,40,179,17,75,179,231,99,49,211,55,97,14,203,74,24,32,16,131,102,169,150,25,102,207,29,7,242,181,206,20,84,221,186,49,99,227,50,100,67,148,152,127,34,167,63,108,61,232,39,121,80,223,189,30,132,217,95,207,194,121,0,156,155,119,87,130,235,79,120,235,133,141,116,199,185,13,227,170,21,188,181,74,141,224,206,240,67,214

这是数组的内容     byte [] array2 = rsaKey.ExportCspBlob(false);

6,2,0,0,0,164,0,0,82,83,65,49,0,4,0,0,1,0,1,0,77,188,48,168,227,207,63,83,106,119,191,209,8,198,213,192,146,215,26,10,247,198,88,9,253,202,191,29,246,136,158,120,101,116,104,226,95,126,127,53,40,179,17,75,179,231,99,49,211,55,97,14,203,74,24,32,16,131,102,169,150,25,102,207,29,7,242,181,206,20,84,221,186,49,99,227,50,100,67,148,152,127,34,167,63,108,61,232,39,121,80,223,189,30,132,217,95,207,194,121,0,156,155,119,87,130,235,79,120,235,133,141,116,199,185,13,227,170,21,188,181,74,141,224,206,240,67,214

1 个答案:

答案 0 :(得分:6)

试试这个:

RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
rsaKey.ImportParameters(rsaParameters);

X509Certificate2 cert = ...

cert.PrivateKey = rsaKey;

cert.Export(X509ContentType.Pkcs12, "password");

由于您仍然遇到不匹配,但找不到密钥之间的任何差异,请尝试插入此检查(它应该复制.NET框架内部的功能):

RSACryptoServiceProvider certKey = (RSACryptoServiceProvider) cert.PublicKey.Key;
byte[] array1 = certKey.ExportCspBlob(false);
byte[] array2 = rsaKey.ExportCspBlob(false);
if(array1.Length!=array2.Length)
  throw new Exception("key mismatch");
for (int i = 8; i < array1.Length; i++){ // skip blobheader
  if (array1[i] != array2[i]){
    throw new Exception("key mismatch");
  }
}

看起来你的钥匙出了问题。您是否可能在颁发证书请求和接收证书之间生成新的RSA密钥?

以下是您的证书请求的转储:

0 30  342: SEQUENCE {
   4 30  194:   SEQUENCE {
   7 02    1:     INTEGER 0
  10 30   27:     SEQUENCE {
  12 31   25:       SET {
  14 30   23:         SEQUENCE {
  16 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
  21 0C   16:           UTF8String 'Daniel Mapletoft'
            :           }
            :         }
            :       }
  39 30  159:     SEQUENCE {
  42 30   13:       SEQUENCE {
  44 06    9:         OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
  55 05    0:         NULL
            :         }
  57 03  141:       BIT STRING 0 unused bits, encapsulates {
  61 30  137:           SEQUENCE {
  64 02  129:             INTEGER
            :               00 95 83 2A AB 16 9D 7F 16 87 40 A4 09 74 5F 9D
            :               81 04 B0 41 C1 75 9C C9 CD D0 52 EF 61 09 EF F5
            :               9B 40 1D D4 79 E0 4B 17 6C 1E 62 73 38 D8 69 92
            :               31 C4 E0 84 07 4B 2E FD 53 6D 24 95 59 12 43 8E
            :               82 35 1D 62 79 89 C2 88 38 57 3D 1F 15 8D B9 CC
            :               FA F4 41 23 BA FD ED 51 69 F7 7A E7 03 72 A2 DA
            :               A9 08 65 17 DA 90 E3 7B C4 2C 85 6A 3F AF 83 AC
            :               E5 00 37 7A 98 14 03 EE 68 37 CB E7 0A 1A 49 5F
            :                       [ Another 1 bytes skipped ]
 196 02    3:             INTEGER 65537
            :             }
            :           }
            :       }
            :     }
 201 30   11:   SEQUENCE {
 203 06    9:     OBJECT IDENTIFIER
            :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
            :     }
 214 03  129:   BIT STRING 0 unused bits
            :     70 D5 29 EB F3 2A 34 13 3F E6 DE 78 35 FB 79 BD
            :     6D ED 8E 89 D9 B0 8F C1 7C 7D 42 37 B8 3E 5B 00
            :     C2 26 A4 E5 77 26 01 86 63 E1 BB 4D 9C CE 7A 10
            :     FF 8E BF 77 1B 0E F9 EE 38 1F 1F A1 04 24 D7 6A
            :     B6 28 3A 88 F5 54 D0 88 46 92 6E 5D 7E 7C CE 87
            :     99 F9 DC 85 99 33 8C 9D BD 73 E2 23 8A 9A 97 B0
            :     3A 9B 36 51 58 FD B7 0F 60 3D FB 5F 4F 06 A0 CE
            :     30 7F 56 B6 53 5E FE 64 7D 8A 30 92 FB BA A4 C6
            :   }

以下是您的证书转储:

   0 30  886: SEQUENCE {
   4 30  606:   SEQUENCE {
   8 A0    3:     [0] {
  10 02    1:       INTEGER 2
            :       }
  13 02   16:     INTEGER
            :       6E F0 A9 78 7D 3C D4 05 4E 90 13 DC 9D 34 77 2C
  31 30   13:     SEQUENCE {
  33 06    9:       OBJECT IDENTIFIER
            :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
  44 05    0:       NULL
            :       }
  46 30   77:     SEQUENCE {
  48 31   11:       SET {
  50 30    9:         SEQUENCE {
  52 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
  57 13    2:           PrintableString 'NZ'
            :           }
            :         }
  61 31   40:       SET {
  63 30   38:         SEQUENCE {
  65 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
  70 13   31:           PrintableString 'First Mortgage Services Limited'
            :           }
            :         }
 103 31   20:       SET {
 105 30   18:         SEQUENCE {
 107 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
 112 13   11:           PrintableString 'FMS Root CA'
            :           }
            :         }
            :       }
 125 30   30:     SEQUENCE {
 127 17   13:       UTCTime '091222000000Z'
 142 17   13:       UTCTime '101222235959Z'
            :       }
 157 30   98:     SEQUENCE {
 159 31   36:       SET {
 161 30   34:         SEQUENCE {
 163 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
 168 14   27:           TeletexString 'First Mortgage Services Ltd'
            :           }
            :         }
 197 31   31:       SET {
 199 30   29:         SEQUENCE {
 201 06    3:           OBJECT IDENTIFIER organizationalUnitName (2 5 4 11)
 206 14   22:           TeletexString 'For Test Purposes Only'
            :           }
            :         }
 230 31   25:       SET {
 232 30   23:         SEQUENCE {
 234 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
 239 14   16:           TeletexString 'Daniel Mapletoft'
            :           }
            :         }
            :       }
 257 30  159:     SEQUENCE {
 260 30   13:       SEQUENCE {
 262 06    9:         OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
 273 05    0:         NULL
            :         }
 275 03  141:       BIT STRING 0 unused bits, encapsulates {
 279 30  137:           SEQUENCE {
 282 02  129:             INTEGER
            :               00 CD 08 AE 3E E3 5A E4 5E 50 28 29 5E 65 05 DA
            :               1A E1 9C 50 44 4A F0 06 AA 75 1A 8F F0 75 4C AA
            :               47 4B D5 8F 04 B5 CE 98 C5 0D 99 54 36 E9 EF 2E
            :               7D CD DF FA 46 B2 7D 76 E5 74 19 AD 3E F0 52 52
            :               C7 F8 86 E6 78 32 90 EB 2F 12 3F 7A 31 4B 15 E9
            :               2A 9D 75 91 EA 31 9F 4E 98 A6 06 81 DD 98 1B 1A
            :               DB FE 1F 2E BD 2E 32 60 5A 54 7C 0E 48 6A AB 6C
            :               C6 F6 E2 F2 FD 4A BE 5A BD E0 DF 0C 21 B6 4C 9E
            :                       [ Another 1 bytes skipped ]
 414 02    3:             INTEGER 65537
            :             }
            :           }
            :       }
 419 A3  192:     [3] {
 422 30  189:       SEQUENCE {
 425 30    9:         SEQUENCE {
 427 06    3:           OBJECT IDENTIFIER basicConstraints (2 5 29 19)
 432 04    2:           OCTET STRING, encapsulates {
 434 30    0:               SEQUENCE {}
            :               }
            :           }
 436 30   14:         SEQUENCE {
 438 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
 443 01    1:           BOOLEAN TRUE
 446 04    4:           OCTET STRING, encapsulates {
 448 03    2:               BIT STRING 5 unused bits
            :                 '101'B
            :               }
            :           }
 452 30   96:         SEQUENCE {
 454 06    3:           OBJECT IDENTIFIER cRLDistributionPoints (2 5 29 31)
 459 01    1:           BOOLEAN TRUE
 462 04   86:           OCTET STRING, encapsulates {
 464 30   84:               SEQUENCE {
 466 30   82:                 SEQUENCE {
 468 A0   80:                   [0] {
 470 A0   78:                     [0] {
 472 86   76:                       [6]
            :                   'http://onsitecrl.verisign.com/FirstMortgageServi'
            :                   'cesLtdPropellc/LatestCRL.crl'
            :                       }
            :                     }
            :                   }
            :                 }
            :               }
            :           }
 550 30   31:         SEQUENCE {
 552 06    3:           OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35)
 557 04   24:           OCTET STRING, encapsulates {
 559 30   22:               SEQUENCE {
 561 80   20:                 [0]
            :                   8B 2A 2C 58 39 03 B2 61 9F 16 E7 3D 3D F1 70 4D
            :                   B1 F3 D4 E2
            :                 }
            :               }
            :           }
 583 30   29:         SEQUENCE {
 585 06    3:           OBJECT IDENTIFIER subjectKeyIdentifier (2 5 29 14)
 590 04   22:           OCTET STRING, encapsulates {
 592 04   20:               OCTET STRING
            :                 3E 91 DB A0 9C B4 A1 CB 68 CC 70 D0 0A 29 D6 BF
            :                 4E 68 10 AB
            :               }
            :           }
            :         }
            :       }
            :     }
 614 30   13:   SEQUENCE {
 616 06    9:     OBJECT IDENTIFIER
            :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
 627 05    0:     NULL
            :     }
 629 03  257:   BIT STRING 0 unused bits
            :     3E C3 A3 F3 5F 3E 29 37 4D 33 E3 F5 F2 89 42 78
            :     AC CD 59 14 E9 CC FF 20 8F 98 34 7B F0 F4 D2 96
            :     EC 58 53 61 E4 3E D0 02 CF FF 30 C8 77 D0 6F 94
            :     37 72 3C B7 90 6E 38 10 59 8C F8 06 B0 61 55 65
            :     58 96 30 7B 9A 58 FF DB 15 7C FA F9 1F 64 5E DC
            :     E8 63 EE EE 90 B1 18 3C 6A 11 62 73 91 CF DE DB
            :     34 F5 67 4F C9 89 77 5C 36 71 FC 11 27 07 C5 76
            :     BB 79 B8 8E 19 E8 E2 5B D7 A5 23 BA D8 19 7C 74
            :             [ Another 128 bytes skipped ]
            :   }

请求中以“00 95 83 2A”开头并且证书中带有“00 CD 08 AE”的INTEGER是公钥的RSA模数。

ExportCspBlob输出中的值相反,因为Microsoft使用little-endian格式,但如果从certKey.ExportCspBlob(false)结束开始,则应识别:205 = 0xCD,8 = 0x08,174 = 0xAE 。 另一方面,rsaKey.ExportCspBlob(false)包含166 = 0xA6,154 = 0x9A,180 = 0xB4,这是另一个RSA模数。

您确定所有转储值都来自同一证书发放流程吗?