跳转至

CertPathBuilder验证证书

总结 + plugin-power作用

  • 主要是验证证书,在输入激活码时,会用idea自签名证书JetProfile CA的公钥验证激活码中的证书(但是这个好像无关紧要,无论成功还是失败激活码验证结果都一样)
  • 比如keys-XIZQAN09CR-idea.key,在sun.security.rsa.RSASignature.engineVerify解密的bytes根本不像是PKCS1Padding数据,所以验证必定失败
    • plugin-power是匹配x、y、z即m(cipherSignature)、e(CAPublicKey)、n(CAPublicKey),返回一个result(其实就是MessageDigest.getInstance("SHA256").digest(ideaKeyCert.getTBSCertificate()

验证代码

 private static void verifyRuleArgs()  
    throws CertificateException, FileNotFoundException, RuntimeException {  
  String powerConfigResult1 = "EQUAL,108391492724719606277191711676038310454333436786970899072879934267610324870870961974305689698304529291751931883693569275416671653649715395540162187908455880751887548211257780817773830153477469379663893839249632010489688404104740814832791608983255964373246023808678041003248593298915323068020141515280275870731964298697511434302901212533563571472947179437111243030002421474283363073021442715554541318313064598900684758246291687123240210640543678544269324094608551763049140564128299834843381841274260516105408318037686490277144538983963856617365418526798235932271319705894170543971766101775628884107261100637290512593943587295268337137890353216997114446658051251047509442298463526766678103653729776506979657957966027949436493606289520405331110453990512846697802196701678785414928082416405650857741201229183421400567636999723106788808933737428330992184832395299929033666381663232693108552887968738513151493044369308652310586803160326722967115451573652070286501044484503083240302303438554529551204609089966636092666792347623413483134664670641246129954999815529917163967761617333572567787618346281658716181608204191963817312534492517480248086896060880038259592723773361709406277837609546030729611710076711450268767610513506889086815865283,65537,860106576952879101192782278876319243486072481962999610484027161162448933268423045647258145695082284265933019120714643752088997312766689988016808929265129401027490891810902278465065056686129972085119605237470899952751915070244375173428976413406363879128531449407795115913715863867259163957682164040613505040314747660800424242248055421184038777878268502955477482203711835548014501087778959157112423823275878824729132393281517778742463067583320091009916141454657614089600126948087954465055321987012989937065785013284988096504657892738536613208311013047138019418152103262155848541574327484510025594166239784429845180875774012229784878903603491426732347994359380330103328705981064044872334790365894924494923595382470094461546336020961505275530597716457288511366082299255537762891238136381924520749228412559219346777184174219999640906007205260040707839706131662149325151230558316068068139406816080119906833578907759960298749494098180107991752250725928647349597506532778539709852254478061194098069801549845163358315116260915270480057699929968468068015735162890213859113563672040630687357054902747438421559817252127187138838514773245413540030800888215961904267348727206110582505606182944023582459006406137831940959195566364811905585377246353->31872219281407242025505148642475109331663948030010491344733687844358944945421064967310388547820970408352359213697487269225694990179009814674781374751323403257628081559561462351695605167675284372388551941279783515209238245831229026662363729380633136520288327292047232179909791526492877475417113579821717193807584807644097527647305469671333646868883650312280989663788656507661713409911267085806708237966730821529702498972114194166091819277582149433578383639532136271637219758962252614390071122773223025154710411681628917523557526099053858210363406122853294409830276270946292893988830514538950951686480580886602618927728470029090747400687617046511462665469446846624685614084264191213318074804549715573780408305977947238915527798680393538207482620648181504876534152430149355791756374642327623133843473947861771150672096834149014464956451480803326284417202116346454345929350148770746553056995922154382822307758515805142704373984019252210715650875853634697920708113806880196144197384637328982263167395073688501517286678083973976140696077590122053014085412828620051470085033364773099146103525313018873319293728800442101520384088109603555959893639842091339193857485407672132882577840295039058621747654642202620767068924079813640067442975";  
  String[] ruleSplit = powerConfigResult1.split("->");  
  String[] argsSplit1 = ruleSplit[0].split(",");  
  String x = argsSplit1[1];  
  String y = argsSplit1[2];  
  String z = argsSplit1[3];  
  CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");  
  String certPath = "C:/Users/LYM/code/break_scripts/license-XIZQAN09CR.crt";  
  String caCertPath = "C:/Users/LYM/code/break_scripts/idea-rootca.crt";  
  X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(  
      new FileInputStream(certPath));  
  X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(  
      new FileInputStream(caCertPath));  

  String mm = new BigInteger(1, cert.getSignature()).toString();  

  RSAPublicKey caPublicKey = (RSAPublicKey) caCert.getPublicKey();  
  String caPublicKeyN = caPublicKey.getModulus().toString();  
  String caPublicKeyE = caPublicKey.getPublicExponent().toString();  

  boolean sigEqualDecryptSig = false;  
  try {  
    Method toByteArrayMethod = RSACore.class.getDeclaredMethod("toByteArray", BigInteger.class,  
        int.class);  
    toByteArrayMethod.setAccessible(true);  
    byte[] replacedDecrypted = (byte[]) toByteArrayMethod.invoke(null,  
        new BigInteger(ruleSplit[1].trim()),  
        RSACore.getByteLength(caPublicKey.getModulus()));  
    RSAPadding padding = RSAPadding.getInstance(RSAPadding.PAD_BLOCKTYPE_1,  
        RSACore.getByteLength(caPublicKey));  
    sigEqualDecryptSig = MessageDigest.isEqual(  
        MessageDigest.getInstance("SHA256").digest(cert.getTBSCertificate()),  
        RSASignature.decodeSignature(ObjectIdentifier.of("2.16.840.1.101.3.4.2.1"),  
            padding.unpad(replacedDecrypted)));  
  } catch (Exception e) {  
    throw new RuntimeException(e);  
  }  
  System.out.printf(  
      "equal x is m? %s, y is e? %s, z is n? %s, sigEqualDecryptSig ? %s\nm=%s\ncaPublicKeyN=%s\ncaPublicKeyE=%s\n",  
      x.equals(mm), y.equals(caPublicKeyE), z.equals(caPublicKeyN), sigEqualDecryptSig,  
      mm, caPublicKeyN, caPublicKeyE  
  );  
}

idea-rootca.crt

MIIFOzCCAyOgAwIBAgIJANJssYOyg3nhMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0EwHhcNMTUxMDAyMTEwMDU2WhcNNDUxMDI0MTEwMDU2WjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0tQuEA8784NabB1+T2XBhpB+2P1qjewHiSajAV8dfIeWJOYGy+ShXiuedj8rL8VCdU+yH7Ux/6IvTcT3nwM/E/3rjJIgLnbZNerFm15Eez+XpWBlm5fDBJhEGhPc89Y31GpTzW0vCLmhJ44XwvYPntWxYISUrqeR3zoUQrCEp1C6mXNXEpqIGIVbJ6JVa/YI+pwbfuP51o0ZtF2rzvgfPzKtkpYQ7m7KgA8g8ktRXyNrz8boiwg7RRPeqs4uL/RK8d2KLpgLqcAB9WDpcEQzPWegbDrFO1F3z4UVNH6hrMfOLGVAxoiQhNFhZj6RumBXlPS0rmCOCkUkWrDr3l6Z3spUVgoeea+QdX682j6t7JnakaOwjzwY777SrZoi9mFFpLVhfb4haq4IWyKSHR3/0BlWXgcgI6w6LXm+V+ZgLVDON52FLcxnfftaBJz2yclEwBohq38rYEpb+28+JBvHJYqcZRaldHYLjjmb8XXvf2MyFeXrSopYkdzCvzmiEJAewrEbPUaTllogUQmnv7Rv9sZ9jfdJ/cEn8e7GSGjHIbnjV2ZMQ9vTpWjvsT/cqatbxzdBo/iEg5i9yohOC9aBfpIHPXFw+fEj7VLvktxZY6qThYXRRus1WErPgxDzVpNp+4gXovAYOxsZak5oTV74ynv1aQ93HSndGkKUE/qA/JECAwEAAaOBhzCBhDAdBgNVHQ4EFgQUo562SGdCEjZBvW3gubSgUouX8bMwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAjrPAZ4xC7sNiSSqh69s3KJD3Ti4etaxcrSnD7r9rJYpKBMviCKZRKFbLv+iaF5JK5QWuWdlgA37ol7mLeoF7aIA9b60Ag2OpgRICRG79QY7ouLviF/yRMqm6yno7NYkGLd61e5Huu+BfT459MWG9RVkG/DY0sGfkyTHJS5xrjBV6hjLG0lf3orwqOlqSNRmhvn9sMzwAP3ILLM5VJC5jNF1zAk0jrqKz64vuA8PLJZlLS9TZJIYwdesCGfnN2AETvzf3qxLcGTF038zKOHUMnjZuFW1ba/12fDK5GJ4i5y+nfDWVZVUDYOPUixEZ1cwzmf9Tx3hR8tRjMWQmHixcNC8XEkVfztID5XeHtDeQ+uPkX+jTDXbRb+77BP6n41briXhm57AwUI3TqqJFvoiFyx5JvVWG3ZqlVaeU/U9e0gxn8qyR+ZA3BGbtUSDDs8LDnE67URzK+L+q0F2BC758lSPNB2qsJeQ63bYyzf0du3wB/gb2+xJijAvscU3KgNpkxfGklvJD/oDUIqZQAnNcHe7QEf8iG2WqaMJIyXZlW3me0rn+cgvxHPt6N4EBh5GgNZR4l0eaFEV+fxVsydOQYo1RIyFMXtafFBqQl6DDxujlFeU3FZ+Bcp12t7dlM4E0/sS1XdL47CfGVj4Bp+/VbF862HmkAbd7shs7sDQkHbU=

keys-XIZQAN09CR-idea.key

XIZQAN09CR-eyJsaWNlbnNlSWQiOiJYSVpRQU4wOUNSIiwibGljZW5zZWVOYW1lIjoia2lkZHkgaW5zZWFtcyIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IlBEQiIsImZhbGxiYWNrRGF0ZSI6IjIwMjUtMDgtMDEiLCJwYWlkVXBUbyI6IjIwMjUtMDgtMDEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFNJIiwiZmFsbGJhY2tEYXRlIjoiMjAyNS0wOC0wMSIsInBhaWRVcFRvIjoiMjAyNS0wOC0wMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUEMiLCJmYWxsYmFja0RhdGUiOiIyMDI1LTA4LTAxIiwicGFpZFVwVG8iOiIyMDI1LTA4LTAxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBDV01QIiwiZmFsbGJhY2tEYXRlIjoiMjAyNS0wOC0wMSIsInBhaWRVcFRvIjoiMjAyNS0wOC0wMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUkIiLCJmYWxsYmFja0RhdGUiOiIyMDI1LTA4LTAxIiwicGFpZFVwVG8iOiIyMDI1LTA4LTAxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBQUyIsImZhbGxiYWNrRGF0ZSI6IjIwMjUtMDgtMDEiLCJwYWlkVXBUbyI6IjIwMjUtMDgtMDEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiSUkiLCJmYWxsYmFja0RhdGUiOiIyMDI1LTA4LTAxIiwicGFpZFVwVG8iOiIyMDI1LTA4LTAxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQR08iLCJmYWxsYmFja0RhdGUiOiIyMDI1LTA4LTAxIiwicGFpZFVwVG8iOiIyMDI1LTA4LTAxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBTVyIsImZhbGxiYWNrRGF0ZSI6IjIwMjUtMDgtMDEiLCJwYWlkVXBUbyI6IjIwMjUtMDgtMDEiLCJleHRlbmRlZCI6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
-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

CertPathBuilder验证证书

  • CertPathBuilder.param
    • targetConstraints(CertSelector),即匹配Cert
      • 匹配方法:SerialNumber,NotBefore、NotAfter、issuer、subject、时间合法等等,基本一致就行
    • trustAnchors:信任证书,做CA的
    • certStores:验证完的Cert
  • CertPathBuilder#build会build2次,searchAllCertStores=false和true的
    • 因为pathCompleted=false,则会返回null,而null就会再执行searchAllCertStores=true
  • depthFirstSearchForward:
    • 主要参数
      • currState:携带userCert和issuerDN
        • 一开始都为null,isInitial=true(即刚开始,userCert肯定是做不了CA的)
      • dN:param.targetSubject,作为CA,该参数无用
      • cpList:已验证或者不需要验证(即userCert)的CACerts
    • param.targetSubject
      • 优先param.targetConstraints(CertSelector)
      • 其次才是用param.targetConstraints在param.certStores选择一个
  • 找CACerts:
    • 如果currState.isInitial,则ForwardBuilder\#getMatchingEECerts
      • 优先certSelector.Certificate
      • 其次params.certStore中的一个非自签名证书
    • 否则ForwardBuilder\#getMatchingCACerts
      • 使用certSelector(currState.issuerDN)在ForwardBuilder.trustCerts(param.trustAnchors)找
      • 根据trustedSubjectDNs(即信任证书的使用者)排序
    • 一般只找一个,上面用的CertSelector,如果currState.isInitial,则是克隆param.targetConstraints,否则创建一个
  • 遍历CACerts
    • CACert校验currState.userCertForwardBuilder\#verifyCert(caCert, currState, caCerts)
      • CACert不能在certList(不能重复使用)
      • CACert不在trustedCerts(param.trustAnchors),则需要检查一下(好像没什么,甚至不需要检查)
      • !currState.isInitial时,currState.cert.verify(cert.getPublicKey(), buildParams.sigProvider())
        • 即第一个不验证(userCert不验证userCert)
        • userCert.verify(caCert.public)
        • buildParams.sigProvider()一般是null
    • !ForwardBuilder\#isPathCompleted(caCert)
      • certList.add(CACert)
      • 调用state.updateState
        • currState.userCert=CACert
        • currState.issuerDN=CACert.IssuerX500Principal
      • CACert.IssuerX500Principal作为dN,递归调用自己(depthFirstSearchForward)
    • ForwardBuilder\#isPathCompleted(CACert)==true条件
      • CACert在params.trustAnchors中
      • 或者trustAnchor无trustedCert时
        • CACert的SubjectX500Principal(CA信息如CN等)、PublicKey与trustAnchor的CA和PublicKey相同
        • 且不是DSAPublicKey或者如果是则DSAPublicKey无param
        • caCert.verify(trustAnchor.publicKey, this.buildParams.sigProvider())
          • 此时caCert是userCert,而传入的无cert的trustAnchor才是CACert
      • 如果完成了,则设置this.trustAnchor=这个trustAnchor
      • 简单来说就是:CAcCert必须是信任的CA才结束,如果还是不信任,就继续那当前CACert的CA验证
        • 开始时传入了有CACert的trustAnchor
        • 或者有CACert的CA信息+PublicKey的trustAnchor且CACert.verify(publicKey)=true(让CA的CA验证CA)
    • ForwardBuilder\#isPathCompleted(CACert):最后
      • 构建CertPath:用appendedCerts(根据cpList,如果最后一个Cert被信任,就不加入)
      • 构建Checkers:
        • PolicyChecker
        • AlgorithmChecker
        • 如果keyParamsNeededFlag,即CACert是DSAPublicKeyWithoutParams,则加入BasicChecker
        • 先用params.CertPathCheckers检查一下有没有RevocationChecker,没有且params.revocationEnabled=true(默认true)则加入new RevocationChecker(builder.trustAnchor, this.buildParams)(使用params的CertStore和Certificates(to CertStore),以及最后一个CA的Publickey)
          • 检查证书是否是撤销的,使用CRL
          • 用CRLSelector从CertStores中根据当前Cert获取CRL对象,根据RevocationChecker.crlDP获取CRL
          • 如果CRLs是空的,则verifyWithSeparateSigningKey
          • 构建一个CertPathBuilder:根据当前的params构建一个新params
            • trustAnchors(最后一个CA的anchor或者params.trustAnchors), targetConstraints(最后一个CA的PublicKey+CA信息即Subject,注意不是CACert)
        • 再把params.CertPathCheckers也加入
      • 遍历appendedCerts使用Checkers
      • 遍历完,设置pathCompleted=true
  • 最后,返回Result,trustAnchor是CA,CertPath是CA颁发的证书