From e9c8d87695b857e6f8a3fcfa0d0dcc55ef1ebba0 Mon Sep 17 00:00:00 2001 From: GME Date: Wed, 24 Oct 2018 21:18:36 +0200 Subject: [PATCH] WELP. --- pom.xml | 5 ++ .../java/blockchain/user/CAEnrollement.java | 27 ++++++++++ src/main/java/blockchain/utility/Util.java | 47 ++++++++++++++++++ src/test/java/blockchain/query/QueryTest.java | 21 +++++++- .../blockchain/utility/UtilEnrollTest.java | 37 ++++++++++++++ .../client/FabricClientWrapper.class | Bin 2976 -> 2981 bytes .../blockchain/configuration/Config.class | Bin 1077 -> 1263 bytes .../blockchain/user/CAEnrollement.class | Bin 0 -> 845 bytes target/classes/blockchain/utility/Util.class | Bin 3819 -> 6156 bytes .../blockchain/query/QueryTest.class | Bin 4627 -> 5329 bytes .../blockchain/utility/UtilEnrollTest.class | Bin 0 -> 2077 bytes 11 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 src/main/java/blockchain/user/CAEnrollement.java create mode 100644 src/test/java/blockchain/utility/UtilEnrollTest.java create mode 100644 target/classes/blockchain/user/CAEnrollement.class create mode 100644 target/test-classes/blockchain/utility/UtilEnrollTest.class diff --git a/pom.xml b/pom.xml index bddd040..38cffd1 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,11 @@ log4j 1.2.17 + + org.bouncycastle + bcprov-jdk15on + 1.60 + diff --git a/src/main/java/blockchain/user/CAEnrollement.java b/src/main/java/blockchain/user/CAEnrollement.java new file mode 100644 index 0000000..f923bab --- /dev/null +++ b/src/main/java/blockchain/user/CAEnrollement.java @@ -0,0 +1,27 @@ +package blockchain.user; + +import org.hyperledger.fabric.sdk.Enrollment; + +import java.io.Serializable; +import java.security.PrivateKey; + +public class CAEnrollement implements Enrollment, Serializable { + private static final long serialVersionUID = 550416591376968096L; + private PrivateKey privateKey; + private String cert; + + public CAEnrollement(PrivateKey pkey, String signedPem){ + this.privateKey=pkey; + this.cert=signedPem; + } + + @Override + public PrivateKey getKey() { + return privateKey; + } + + @Override + public String getCert() { + return cert; + } +} diff --git a/src/main/java/blockchain/utility/Util.java b/src/main/java/blockchain/utility/Util.java index 464c9b1..621e99f 100644 --- a/src/main/java/blockchain/utility/Util.java +++ b/src/main/java/blockchain/utility/Util.java @@ -1,10 +1,22 @@ package blockchain.utility; +import blockchain.user.CAEnrollement; import blockchain.user.UserContext; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; +import org.bouncycastle.crypto.CryptoException; +import javax.xml.bind.DatatypeConverter; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; public class Util { private static Logger logger = Logger.getLogger(Util.class); @@ -84,4 +96,39 @@ public class Util { return userContext; } } + + public static CAEnrollement getEnrollement(String keyFolderPath, String keyFileName, String certFolderPath, String certFileName) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, CryptoException { + PrivateKey key = null; + String certificate = null; + InputStream isKey = null; + BufferedReader brKey = null; + + try{ + Security.addProvider(new BouncyCastleProvider()); + String keyPath = keyFolderPath+"/"+keyFileName; + isKey = new FileInputStream(keyPath); + brKey = new BufferedReader(new InputStreamReader(isKey)); + StringBuilder keyBuilder = new StringBuilder(); + + for(String line = brKey.readLine(); line != null; line = brKey.readLine()){ + if(line.indexOf("PRIVATE") == -1){ + keyBuilder.append(line); + } + } + + certificate = new String(Files.readAllBytes(Paths.get(certFolderPath,certFileName))); + + byte[] encoded = DatatypeConverter.parseBase64Binary(keyBuilder.toString()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + KeyFactory kf = KeyFactory.getInstance("ECDSA"); + key = kf.generatePrivate(keySpec); + + }finally { + isKey.close(); + brKey.close(); + } + + CAEnrollement enrollment = new CAEnrollement(key,certificate); + return enrollment; + } } diff --git a/src/test/java/blockchain/query/QueryTest.java b/src/test/java/blockchain/query/QueryTest.java index 7f5ff95..6af5304 100644 --- a/src/test/java/blockchain/query/QueryTest.java +++ b/src/test/java/blockchain/query/QueryTest.java @@ -10,6 +10,7 @@ import org.apache.log4j.Logger; import org.hyperledger.fabric.sdk.*; import org.junit.Test; +import java.io.File; import java.util.Collection; import java.util.Set; @@ -19,8 +20,26 @@ public class QueryTest { @Test public void TestAQueryChannels() { BasicConfigurator.configure(); - UserContext admin = Util.readUserContext(Config.ORG1,Config.ADMIN); + + //UserContext admin = Util.readUserContext(Config.ORG1,Config.ADMIN); + try{ + + //TEST FAILED + + UserContext admin = new UserContext(); + File pkFolder = new File(Config.ADMIN_KEY_PATH); + File[] pkFile = pkFolder.listFiles(); + File certFolder = new File(Config.ADMIN_CERT_PATH); + File[] certFile = certFolder.listFiles(); + admin.setName(Config.ADMIN); + admin.setMspId(Config.ORG1_MSP); + admin.setAffiliation(Config.ORG1); + Enrollment enrollAdmin = Util.getEnrollement(Config.ADMIN_KEY_PATH, pkFile[0].getName(), Config.ADMIN_CERT_PATH, certFile[0].getName()); + admin.setEnrollment(enrollAdmin); + + //END TEST + String chaincode = Config.CHAINCODE_NAME; FabricClientWrapper fabricClientWrapper = new FabricClientWrapper(admin); ChannelClientWrapper channelClientWrapper = fabricClientWrapper.createChannelClient(Config.CHANNEL_NAME); diff --git a/src/test/java/blockchain/utility/UtilEnrollTest.java b/src/test/java/blockchain/utility/UtilEnrollTest.java new file mode 100644 index 0000000..63d812b --- /dev/null +++ b/src/test/java/blockchain/utility/UtilEnrollTest.java @@ -0,0 +1,37 @@ +package blockchain.utility; + +import blockchain.configuration.Config; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.hyperledger.fabric.sdk.Enrollment; +import org.junit.Test; + +import java.io.File; + +public class UtilEnrollTest { + private static Logger logger = Logger.getLogger(UtilTest.class); + + @Test + public void TestAGetEnrollement(){ + BasicConfigurator.configure(); + + try{ + logger.info("----- START TEST ----"); + File pkFolder = new File(Config.ADMIN_KEY_PATH); + File[] pkFile = pkFolder.listFiles(); + File certFolder = new File(Config.ADMIN_CERT_PATH); + File[] certFile = certFolder.listFiles(); + logger.info("----- GET ENROLLEMENT ----"); + Enrollment enrollAdmin = Util.getEnrollement(Config.ADMIN_KEY_PATH, pkFile[0].getName(), Config.ADMIN_CERT_PATH, certFile[0].getName()); + + logger.info("KEY : "+enrollAdmin.getKey()); + logger.info("CERT : "+enrollAdmin.getCert()); + + + }catch (Exception e){ + e.printStackTrace(); + } + + + } +} diff --git a/target/classes/blockchain/client/FabricClientWrapper.class b/target/classes/blockchain/client/FabricClientWrapper.class index 904b4f6332f8d96265bf963f5812a8f754923092..219bcf4c691176571d215063758979d9a1b7bde9 100644 GIT binary patch delta 28 icmZ1=zEpg}XJ&rB+{)yP#Js%JoOmEBdGlZ9#q0o~Yztlh delta 23 ecmZ1~zCe7#XJ#(W+{)yP#Js%JoXt!ui`fBb$_P&Y diff --git a/target/classes/blockchain/configuration/Config.class b/target/classes/blockchain/configuration/Config.class index e556f14213571e405e2aa8de7c15f26833b4fac6..3e21f238a85e14c0b67101364a97d074e3dda741 100644 GIT binary patch delta 555 zcmZ9JOD_Xa6vzL!HC!|rl192z?`I$0Z)4`7QBy_{t4ULnXlRMC(3OQfY37qyh_LVh zd<83?Kzspl=1xi3oSgH!|MNfRU^9z6ph$bXk5Jaj8bVkr2xeboh-@`V=VU20OLQR;t8r0n+yK$dbObKBCgYFx<4Y!pl zh2wm=Y@b?`6=tdMhb#*V*eRXv|DVet=#Ubj5%NkII9uc^g7Q+-934?}= SPz=dj!6?S4V$|XdN_+!~2yyWM delta 372 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 delta 1627 zcmY+DTWpk75XXOKySwMx?Q)TV1r%6BD0IQL+{98qC|GW7DO5p3VGG-`we6N=TUrpd zT)d!AEh|_rs7OqVi7})J5)&19G0_JTVnPg0#uyVx^uZU6vGxCL+YL6`bLPx9znM8R zbIz3BnU?-`@bfQ$#e5KC0lR`c%`*Wa?6&L);$@dZ)ZH6`%w?~`K6j6~n#Lea?01Me zG&?+NX$dl(R(EN0NVt2uGMzbU*No9a^|{cvJ;||Hw;rVy`HHJ?xA0Y`eb+b zP&P)Qp*glU6>dxg)%H?j&?>%;)#+C zwd=a}#@bWyL|cfrDa+K^1$pl%r{i{+a=IAeUEa%lZNnK)V2YRbxs;g^m{c@A%eO?^ zno8t1-qtkgGOMcJpG+KzHnhYB{tjF*nSaMr?1*R@zz}pRCCMvU1=PAwrxNW(yRY~& z%oPb97HRcol>to?goX`R!cv_AJj^m_77p}{{l%nR3`fOpxD+Jf=Bl z;$99gnQo?Vj;Zu(MlLg*Pnf|~!rWvgwBz=NicB6A;e%`E1bA{LlpA|}FoQ=-vWM5$S>!mpBpHF8iX z2UT*gkvV3wxGmy#h}$J@x45XdMsdyJlHxkWb&ES9u1DNS-QTTBFJpDVbRUmUuA4W} zt}2wPx(8^af)%R7Wf`uNexdufh)NA~{`UPKt_mzd8y$BB_a|Sj`#* z_n9=6tVNqOM_H##JXGmJD-(xQW4~p+WrJm-WmERI8UCVXjiuT<&RwhYfB*lEHACEk zlLO^UjjRFJ$e(5WLyD4jw?)9AmMz(7I6R?Zcp9!|=dE0(%XOOyIax`u?y^L;S)u%^ zbb~r&zmpB@W+VHkR`oU!XESYbmz2X!wrOJOIKozXsON;PcuJQ%Ev8pYM$82<{bDYP zxg_R8wx#(<(8q#46?BF53<$U;;0poQ1>6wujeze2e6JukW&eZhf0X@bSBo`rZYzCC zdG<&H<0DP*DW&0d_>|D7)ITDneF{FRyfGp<3Xtod=Dbd>-M`xkTdvZ16x{8qN7cHe zl>XSVL!Ejt3)j@azFTFn`sJ8!M_OHngOeztcxeYGElCv$Ip dX7)krDNl%8WBven?z=a4z5Ad}JEimR)PL}v577Vs diff --git a/target/test-classes/blockchain/query/QueryTest.class b/target/test-classes/blockchain/query/QueryTest.class index 18780f12e7c3f1a83b6bb4ecb7c8d7b43bfc8f80..f3af98de845c18e381f733cf31816cb2e412aa1b 100644 GIT binary patch delta 2179 zcmZXV33yc16~})!nVI|M&C4Y7vfw0$fY}ogAc4SO(Xd%CKq*ujZP5^hWMDFZ%t)o% z)V69{iq$^4(2Y{t(rVR0>PT+%_hkEjqoh?S!^(?AF%kK(H}D6 z!)9^6%}4mCaX)79am^=eDmY;ANuv+ie2UwR^=XUGSbWyz5TCR1eBR;?W8Z1<1&h0k zdAH3ye9?%*MjSC>RCBMzmn?j9&{%|{9E)(AaU;I0xzDDJ`)ztSp?SbKU$L2Es&3<} zHVu3&%woQ-`G!pwdn~?b^tbAbe9-10PMY+GHIEqQ+nVnvLh0dwf#irH?j4NQcoB7j zI_2$E_jqTE8#h@ywyzjYZ!yc!o^5@*`r1>&?JH90&0bZoHa}%3yQ95O zfGIxPzCF1+n;RZUIxOW$hadA3LE>dOeWqU1Mb_b`JgEq*9T}M8@H4aH=SKX3r!;3A ze#x&Ke$8(rWoUPQzoKq)dbodk|6pG#)83y>CB18d7t}B1w}Pi64EAL*$@DcQ)!}#i zUYd0H15Z1g<&WO}V1qY16m=HNo;OGHCx<`tjQ2#aW=dCAXUE*O;a!7mnPe^@%N-8S z@)yquEvWu0e-oS>{?2m_|KOhv|Ki^c|KVwGQ)oub^GpbC4(AjCo}-j1a#XPjC|bPR z?5SRJQK{{ypb8nGy+=b+%9X`ajtVPVAW{*BZkBixp{BTUREeXa(zz;iRGEr7%4M0N z+FPfpr#Y%zRVc~|7m)7D479J^ye-+E)2dR@A-`4QosP!r+V#1<+;v$2%7jW@B7>sd zJ6KfjJ*%HdRyIx&tZ>Zw+(;@ju&C)uML3usdTC@ml_rt>VZO*x3{F)J7ZP5QSm41NE%iuQeIiO&YK-^~t#0rt2LNLbVVmp%wypomTDOSnmBD1-;O=eYvgjOA;Xq@8SF#Vx8w4=7jG2p_|zIL71W9Lsoxm5kA~i2w{d+U8V|>{+Z2!bG$%^qrN?MdB+BAt z$7ogTr`K4s6c5mrh{a<*?Fl#T`pk~;-~r0UnbT{cbI0g7F-}9i;B}5MFHwGk`Qvm6 zObgtFK8bj_2%kkhmmE5G`ys5J7N1uf7Kn>gw^}AsG*GyVTew(&uacXaMudx~WIEN% zppKce%GzA97Emu!xq%Hda+O3kF^fT&*gNyg=6X5mCOX*1JQ?}(xkE(v8w%tE%K`i3KJ7EU)AB zLcdL%k?%SgAcH*4HC&6uPEOIsX2R0YL-eynIDHf2B-tvs?Bgy5B-@b|50GLTCDPcg zJljbVmHtu;k)c$&2r$eJ!)mqa1y=8Tf#;K1Bb1Vr$OeMvWbDQ?In8yNU79z%D6iM- z*1S>kCe52QZ_&I}lh?dWbA#sX@I0NGcj&FW^Bm16IRlnxZVX7xlMn1>(H8Ie-&>qv pN|I05U3`>FN11QlqdMna#}?8SE78i((5w(A1aVLtN!!M3(X!2M zi&jczrDbMFT~JapTg=R~eKFh1vh+iJEjw3w>O=E9bGG+A=l<_G|8o!K+qv<*e{I_V z4CgmXM9g9VZHntm7Me`6Sj6=vHz;njFuBR(W>?287ITYhEit*(~S+j$kQd{#XyELz{+dh&oG-Fgn zWm!c@OWUlHXe1UMRW?G3ysmkJH|>0tnfAZqVVbwtV^33+8E>;!fNI`hpXOcmYu@94 z<{-Q5O)4kzeLfK2nh*I%&}%;C6V0c5W>9DwzCug$IbXQqkey|wrSm0+H6!^-^EKbN z*0-7woNkXZ^Hceb?=?SgSn;FgCyr=-mKR@YW@YdTM-5V%>e}i`o9m(tr4wf~Me1XU zU+tY{rG3bk)tT*2H;U6{G`G~xmS!|YOBci%n;T<`N^3+LB)3NDX4cG)w2p0w#v%)2 z24n4ZJ=87^q}Zzix^r3JOt0N;rKR@E8~@*9CdFDCqYb0;CwJ~nE;Zs6LRm1dT+Cwi z5nE;?a+G+bq7Bi$f-Z~>F+7AtCY%hWFj{Qgdx0}JQ#^ySB-!I8d)n}lEU`bj@dUj= zUpEQkgQ~g*v$n7c|AgY8<-`euy&WQUY+!bzuZFz9efSeaAGLYA-6Ak+DYkQaIG61(#6o7JyO(l^18?mCvBmihr-$} zih_cyB$On=q12&l{fTw!F{_Il$~&YN0giG^7Rh_EYfWTGH~LA7Q{^O`Btpc~B$!Qq zhLFWD2FSwZP%TSZ!yu-UOGMIVlSdl`ERpS8OOb43F`bkM@-p^Q&JkJVqcXK)GQ;CC z#oy&|?r2s@`!`6%vl&aG+|1xy&XdQkr&fB6#f?5NVXLq210?PF}bvuK-ALo5}-83HKfIu6g#vu=|z?ovsjiKNzRlP z$PE3_JVt+~oiVhT=>znI`mfWok_jd*(@HbDdoFt}-`TVK=ik5o0pJdvBya_H6Ij4v z9G9`A;^PFC@ri!lPWl-VQm|(kaUL`_4kCwaJ^8m9J6lj8N$|E zzOaOUpg*KJZ@Z3VmAU7Wr(ro~*SH^Yd4tz`~?10v8&^1x-b+7LFw+d<-c2Tkr;yh>Q;yGF$ortVeidKiX`f?P53 zG8#Iu47;Z1e=vE|7miJ`3nkw$>l;Qh$ePe5M7LVDFB*JXc!J=_+P32xQk~Ek3Y_k@ z2v)t5y1Haq9heg(r{$VF%xm~8NVjGF8q%0ju%qE?Olf!%S1GbN`K3$c>{dBl&X>w* zNh^4y;W55p(7J(RxY|_?)3J9&t>p&M>A8Sn7;AV4mh0UDOopX%N_#L|uc03WJi%Q?^o}A<5xWL$8XX!NwHBWLLi3$4{cK!9kN@ z>Kv8R6H0|U^{`pl=O&%bYdwv#VtB#~VU(acbZ+A(7|V2fHiVr~@I#~me%unC9~6n<;&i5`5tJJDi$;T7k4$H}Om|FBMCW8q{YG2Q^rGmFtz)3q z`>N_DcbVA8Rjv9h4s3sk4Ke#8#u3=I&;v_pM{cLxN zIm__8#mu=^GN$O2xI#|{Lqc{xts=ChOM%8~MCmj$nqxCZU@vIVhwC)<2h1dH&{_)> za1(D4MfV_W?vtC@J;X>8cz%q&Ul2(}+lakH|4vFhLcDORjl@PkCW$Q05xEeRY8t7f z)Y-^<8y8Z^@o2C(#=t_1q%SeJbA+MP#WqsovEMMv(8fp`qqM0@e5oTIlj2k;{u!!t zI{t!!jNlm#=^cv%=`3J?!W<%M7)gv^l>P}^qV&cvLt66~rzdg}HA3qdrFTe3{YWVN zL>dx;`%q}d6HFsRwkPOHnZYdr;RY(0C0>N+$Cx8tlysMIn{bVhg(%*^y8(R9JMhhu zwK)3z!l8oqqV%GNSieuRiVt3uMV3c?@zlgICVxdlmWJL&8pG1aqI^hHA3pjA=Xwu) literal 0 HcmV?d00001