From a08ba86acf13dc20d42642b5268b151b356a3cd7 Mon Sep 17 00:00:00 2001 From: jjg-123 Date: Wed, 1 Jan 2025 08:01:45 -0600 Subject: [PATCH] https://github.com/ncsa/qdl/issues/92 partial fix. Unit tests added. --- language/buildNumber.properties | 4 +- language/src/main/docs/crypto.odt | Bin 53793 -> 56453 bytes .../qdl_lang/evaluate/SystemEvaluator.java | 3 +- .../qdl_lang/extensions/crypto/Crypto.java | 147 ++++++++----- .../extensions/crypto/CryptoModule.java | 4 + .../test/java/org/qdl_lang/CryptoTest.java | 202 ++++++++++++++++++ .../src/test/java/org/qdl_lang/TestSuite.java | 9 +- tests/src/test/resources/crypto/aes.qdl | 10 + tests/src/test/resources/crypto/ec.qdl | 15 ++ tests/src/test/resources/crypto/ec_public.qdl | 10 + tests/src/test/resources/crypto/github.pem | 27 +++ tests/src/test/resources/crypto/pkcs1.pem | 27 +++ .../test/resources/crypto/pkcs1_public.pem | 8 + tests/src/test/resources/crypto/pkcs8.pem | 28 +++ .../test/resources/crypto/pkcs8_public.pem | 9 + tests/src/test/resources/crypto/readme.txt | 4 + tests/src/test/resources/crypto/rsa.qdl | 19 ++ .../src/test/resources/crypto/rsa_public.qdl | 10 + 18 files changed, 470 insertions(+), 66 deletions(-) create mode 100644 tests/src/test/java/org/qdl_lang/CryptoTest.java create mode 100644 tests/src/test/resources/crypto/aes.qdl create mode 100644 tests/src/test/resources/crypto/ec.qdl create mode 100644 tests/src/test/resources/crypto/ec_public.qdl create mode 100644 tests/src/test/resources/crypto/github.pem create mode 100644 tests/src/test/resources/crypto/pkcs1.pem create mode 100644 tests/src/test/resources/crypto/pkcs1_public.pem create mode 100644 tests/src/test/resources/crypto/pkcs8.pem create mode 100644 tests/src/test/resources/crypto/pkcs8_public.pem create mode 100644 tests/src/test/resources/crypto/readme.txt create mode 100644 tests/src/test/resources/crypto/rsa.qdl create mode 100644 tests/src/test/resources/crypto/rsa_public.qdl diff --git a/language/buildNumber.properties b/language/buildNumber.properties index 571dce803..a9ec2b4cc 100644 --- a/language/buildNumber.properties +++ b/language/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Sat Dec 28 07:19:34 CST 2024 -buildNumber\\d*=13761 +#Mon Dec 30 08:03:09 CST 2024 +buildNumber\\d*=13765 diff --git a/language/src/main/docs/crypto.odt b/language/src/main/docs/crypto.odt index 86f6435228dcb88db15c69280b6521909fbde178..4b975aea09d908b3a0b526f55ee5149134802d5a 100644 GIT binary patch delta 51684 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 NV0nkpB4qEp^j{Uh5SIV| delta 49050 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 z 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℘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 = z3ET#Saf@5FT3su9_CNF77I1AiRvAcE6o3odjvpb3&gr0Ud8 z_?vmjEd7Yg=3}A5hC*@zPOSRYb_zvOs!a0}%ZR3$-YrORzqtLB`3zkoDOB$g)F zxg$L!u1LM-ewJ2xWoj3%KzGRC=n$*UtXi70HjlNBDDpEwzAN^)==nZWdQrD)`DjA$ zOyOu}fGLbmorLB(3v6t2-Mb|$qN11k3Jcs1@({o?x&@fhi@DMOih&?bhKwgz=2Bci zXquV^3=`^KFvS_;{Y489C_lvZmo-Ez!ucK$F348!e^ND+K|`CzK2Gm)QitCcAzgCN zZ!cm>zo5#K6IJj7wD#8m+^2eU%ohmH)kJAn2N*o8`z3T5B$I1T2dt)qCtSpkV9dJ$ z#|B>oBZaF_!W}39Ex*#&oj~#2&QaJAomD_%pj{MSck8lpXtm@z_xm8XbGlt=N@>UoQz~Oz zH|EK&5e;M9WniWaUg!gCj?QbgbAyR_siGzT%%z`bBYOzIuAj7&u=^<qJk;W8gzQ0`+jM}ncMflxhgG1rLhJ3!+KvxZ| zGtdf9FA7X9(MzeOW`YaQq?kVM>^hpRJ!AH)qBSSD+s7hH)=#RY7$UkS9 zhfe-_mrsc(1xZ2zL3N56jumt`P_u$YTuhr)=Qj(8?p56sTp3!|G4XK)L zIMfuJ_Qs*(_ku;L@PfdUBS3HmZCR7@Gqf;)(}#XR4bl37(vbQP43`;RA!>{HlXC## zgVzs<8sv*c7hzyV>%@;;x;zMyE8)9 z62$u4wM*USw<-Sqp0(#y<4*Ye+Y*ZRF-5ND}DH-h6?Li3i74Lh;c7ADpHa$IZ2Yb ze3ud%n#2LE@(1#EL%rbscTp1_{9H)+A(&<^O~^C`<7!;y%pcjRJ;X;>L{VVcSSx&< zWPWfL3by6Pts$vKOXLjkuDJr*Z8!`}#%)yf&#D47J8}wQAjZ1cPW8g5B|@lq3xIic>n!q{wsUwprDph=;S7A*<|aZtnLVJ6F zifvxyx9R7G8Y5Uq62T0+9&mU>%j4k-f}fvAP$%` zP2DIHwwr!HqW-?5&mhJbFhYCp45b-lC*BlP=uNqlr`_C+rSWbAWz>~IT2VBk{ zRZ;zh<{A;UE|3@7Z-?X2s$H7oUsox5^^-aJd=k9A@h}N*-5L*|o)i!+!?$3|4n&SZ zV11uGHMSP;m}%o_0b}Q)rt~203Itir&0N_fZx@x=lz?)#{)Qx+yRMM0VB$0ouXR@8 z|1z;=MuEPfMjEHG`PvPB$R}{Vpg-5twkA{pYeX|8dO8w_vI%;e8=R)o9j{nn zTldRl6|C9f5Z;f;7GTm$;foN}kKj4*^=}GoWObK7f4*|4RiQP2dyP|o9o6AUK2R=g zNRp)-EJWh`i?)0+i)4d+?Yd{5My4T2LN|bi9M(UNh1d%I&dno0ukSRtzwY@`s6)39 zd-F^E@V53rkB$J}O*`1|rDTRi{e0A9;~JcRMA&8cv>-651_&KkVQp|l1in{WE&Gj+ z9)7eD5_=o}k*yJ3st1W;%POX!?u)R!lwvcn_{_C5$beps={2ahR&H~ z{?_NA)Uc;|st;4_9j0bj=LSakRxEaB?ID3?wkOCHA&3`tPNR2c5r~a=>35JhXDBga z3^q_O*A(9*07uo(7-*?gyKKZZN1C>6X#~&K8JKt80yzprdtJh5dBz+K6dObRxuxD5 ziPMEjH&BPWJg9gm-x>y5lA`-__yWb&o_xptUTnhAGpZ&HD`xEHxepMsND>oBPg*Yb(qdj0&ccKRlAxAY;tV>u#(c+YuZQm5mq}3-6Q!Xw6tx zWhrvdXL3{og1h1i(WZahdJtdA6l&_|SDTJ0rh`p>TFcbw)FVGG=GU2+TjU}o>=cAw z&mIq#0C}!xs|PY*&CbNjax0F(PJT_?`}7Nz)9ZjHq3WwBpP1-eRQsh9K>;E>COND` z+EbJ8i@w#)(_$d##EdH6Tl`Ubl7&&`Mkyhg!}p^+#nY8nWvjBc z2ynOI3vceU6R!H(FjoH4mu=i;zRlK z7vZpknQm%1E6$D%@`2WLp}bd6E_v93iSy85=d~jWVvPBoXRf4%oKg(Aw4~q2PV}DJ zkk#5CG7&)fK%Fmo)+3ASD1NBs?)v5V9vCp?W9psMeLn1X4nsHi2`x!{Rm36@5Jso& zqgV$QgDDHunCtNEByB6J#}v7;6Os5R4SsTT`RVba@7@A_(gJeYGHK!qJXb$IiozA1 zPHO>#x6_svtTE`hEMb00uqEYKWQ+n-41%trQc?$sPkSHjESJRB=v2(PkEgR=f7?M9c2iz55F%r=nj8&dAT_Nn+j-ko`3X` zF7FEDA75VUR(NcA%?e7=8DmX9E+3!Uwj;|$0=;W(uP)Y8dmqN{#!FJUy1V36&lhp^ z+6B9xm(<7X!u>PPwLBUDb*iMSGVY2tO9dSM4a$Y`HSM;luC6L34}JbbTdmfOo55s{ zLQu7h-km!uzLpmzPS`8N54UVNL5J^{v4gx+ae~H`{Cz*Sv3Jnyk3(?g3|Z z>?U9yJY}-=vlN7|4c4z}{LvJ*B+rr@RF{%dC9J+kKMiu7Lc&nNO>ry~omP%b`fEo*w;GZ7Sn^lDr^Ia`wZVW}z{p_K>uh*c3qSn;{gSo( zYai(g77o2O`FA!7!1olJvPAU-EBv znJC;#Bk|M|@`IoEs#1cM|6Xg{Zz2w|pjS#vg1!5)5+FeJ0dv28X;do|7)GAHJi^Gz z)i|{*i%1YLFiR+`AZVldY3x`WDKmL8-I4@n0T_Hrx4K@|X=jL_9V~J)m}m{u;rgzq8DsJ;@S`-ZhaTsmd#*n z4db(jvY=qQ0c??5hOT-){;UH;a_>*ue<%f@!-i&{icKv~5?czz=@aATsJU2vRFy<~ zzq0HfPimSz8a3k&Ty*pG7tfxX8!gHXo-#fRMcjqzbzO1mlz^D!%t-laY|#oT&?vlM zQI3-m{<$xBzN_xG^(G(htXn(bE8@qv$NhNU%dS341qSb2_f`D2-w=dY#>{BK*BZtd zJFQ!_m+aup-8Fe!tKbE;D=3cLkyH^Firs3*V6U!g`dXd@eWicj2~L;S{29;De@lUz zCW$Bfyhjl>GxGKAfY3RHqAS!`)c4gT2a$Ll@_rfe1Kn&3bEc}I9@>LpVjEgA&3P(O zy0B%25=hBH>JLwcADv`kPq^7d*PY#T_yYw^qeC^OJg>pFSt`wf+(K5fQgzfs@1jbf zx|8PYvxONOe@S2egPQ#*g~8~`nISd9&4b4Q&+FMVy_FNL+Q|;hLfJgO^c}=RK-*PE$cZhu<9bzB8Z%XS8+$15juh%zHi2ly- z<;L3HEWn23icJb@#`6wIcDYgF5jam!GNPb4UqhK6qiZjN_@=hcTmP&(g-W_3p_~9+ zfh32+OinIo5Wnrh$Kd%iK*wj9Lbq2y0ASlWEMpqfL(4?*vLOs+fk}W?QEjH!Mshxs zt2`XKJ1=@jtMgLIwC?@pM^&Gw2&K(8oU61}kX|NS|N4`2kUs+LK?%8kEK$m+P`7G! zBx*zG~JO%`|5AS*XOuIWhzP4D5rA3LsPz zgM#5ZZC*h+s;gL6lE7HxDXAWkyrV>LUl4MiWg%Wa1YV;ONu0Fj4~Heq-)$jSFb;fF zpN{5jv;1=}_Y(zK*S-%|-5;AwMB6j8`Rwd0CelXOI*I5zT(h;P$%X ziY=A@0Nz9rg%AR0qrp=N6>C}%pdN&6-uTOwCyO@Z68ZRr0qDkvY4Ua*(T$_LsIs?k z^U*O{xRm3egV(%zRfvOlpY;cm>D2;VA-&-K`#8*Q@ncX199-Ts_%0T`4Dhi$*$36; z;nOYUwYiuePj*F`X{zMRH30>WpOuKf+0y0hL|3MtBvx(BMWO;-q%bWQ`H52~i?yTD z{95TMN`VuaV=-2L{Aj3LHJ9kxSNK~9LSRjc=1Nr&qHXGOD`yA!K>rE5&}=6FSQ{4h z`{jw_gXm&she)X{uRJ&P4p;_UpIL}*!&M}CPn(NLja{$mP*4}YsO%_kL2Z~DwsfnN zMb1DzoInKu;+*x9?!Rx{(6YY!34fI#K9(#0Iwib6nh&f41AoDQmv`{~iC2Gpxe;lKnB$a2~USDA!DKMb?seZUi3qU*NSM zy?RF@{kYNqM8lC?{=cxa-Njg0vB4!>7-pD#jz_9eccMkwmx+O|3NA_k;8C!Z~4$l!ZP3w8)s)0Pe(d9`gx)oJ`xs zLQaPf9V&?}*F753**^tDe)0r!Yi{5Tau**2L}v(LU7>L9h^rN9dD=W37Zc00WE5_Y ztW$zFVdE$8gS2%4EEq$U!INmX@zqoZFJviNj7cHoZMz_^o|y>oaYfdWN9of|l)xW* zwMKRlCW%E{TUG;)n*N-qU&i%@pogZHhos2iv>!t6P?%AN%OdY}^}>+P9{YPIu5Y6>SuhD|#xj2f~h@!TMb~Kf0H&>k=fme9{;W`L$IM?_{Xv5cA=V z*V+6tc|IULnwC&!5q&Pc;CdpEmBO2N#gQq|`JEzsc}75{>Pp2%Ab;}2q2`qt5U3hw z;rLr)AzGGbHGZ&2uJy2TZjlRFwC@8`J9|Yv37!*WN1{4ep1PufP8UzHxAzM>#hy|V!1O((CB~q+V z{KpwRV+AMCas@3>01O`Sf8!IoS8>3CK@zLiFcN_^r2mG4wSy!QuTlM{{SR{olDNJ~ zLHKWtPuBna5dL@VUxhj`dX?cna}-x_z|24skwJ<6e=FvKCjR*!!htRQL!u^*uKdT3 zKJnjdM6g8b6$>pp2>SoR;Kn2pZjg%n s1N~2>!~HK%WGo1Xv7N26sjV}EyN$J?3 dd) { dd.add(" " + JWKS_TYPE + " - (default) JWKS key or set of keys"); dd.add(" " + PKCS_1_TYPE + " - PKCS 1, PEM encoded RSA private key"); dd.add(" " + PKCS_8_TYPE + " - PKCS 8, PEM encoded unencrypted private key"); - dd.add(" " + X509_TYPE + " - X509, PEM encoded public key"); + dd.add(" " + PKCS_8_PUBLIC_TYPE + " - PKCS 8 public, PEM encoded public key"); + dd.add(" " + X509_TYPE + " - \"X509\", PEM encoded public key. This is really PKCS 8 public, but used in X 509 certificates."); } public Object importPKCS(Object[] objects, State state) throws Throwable { @@ -323,6 +325,7 @@ public Object importPKCS(Object[] objects, State state) throws Throwable { privateKey = KeyUtil.fromPKCS8PEM(rawFile); break; case X509_TYPE: + case PKCS_8_PUBLIC_TYPE: publicKey = KeyUtil.fromX509PEM(rawFile); break; default: @@ -495,6 +498,7 @@ protected Object exportPKCS(Object[] objects, State state) throws Throwable { content = KeyUtil.toPKCS8PEM(jwk.privateKey); break; case X509_TYPE: + case PKCS_8_PUBLIC_TYPE: content = KeyUtil.toX509PEM(jwk.publicKey); break; default: @@ -505,9 +509,45 @@ protected Object exportPKCS(Object[] objects, State state) throws Throwable { } public static final String JWKS_TYPE = "jwks"; - public static final String PKCS_1_TYPE = "pkcs_1"; - public static final String PKCS_8_TYPE = "pkcs_8"; + public static final String PKCS_1_TYPE = "pkcs1"; + public static final String PKCS_8_TYPE = "pkcs8"; + public static final String PKCS_8_PUBLIC_TYPE = "public"; public static final String X509_TYPE = "x509"; + public static final String RSA_TYPE = "rsa"; + public static final String EC_TYPE = "elliptic"; + public static final String AES_TYPE = "aes"; + QDLStem types; + + public QDLStem getKeyTypes() { + if (types == null) { + types = new QDLStem(); + types.put("jwks", JWKS_TYPE); + types.put("pkcs1", PKCS_1_TYPE); + types.put("pkcs8", PKCS_8_TYPE); + types.put("public", PKCS_8_PUBLIC_TYPE); + types.put("x509", X509_TYPE); + types.put("rsa", RSA_TYPE); + types.put("ec", EC_TYPE); + types.put("aes", AES_TYPE); + } + return types; + } + + public static String KEY_TYPES_STEM_NAME = "$$KEY_TYPE."; + + public class KeyType implements QDLVariable { + QDLStem keyTypes = null; + + @Override + public String getName() { + return KEY_TYPES_STEM_NAME; + } + + @Override + public Object getValue() { + return getKeyTypes(); + } + } private JWK getJwk(PublicKey publicKey) { @@ -685,17 +725,16 @@ public List getDocumentation(int argCount) { List dd = new ArrayList<>(); switch (argCount) { case 2: - dd.add(getName() + "(key., arg|arg.) - encrypt a string or stem of them. If the key is symmetric, do symmetric encryption, otherwise encrypt with the private key"); + dd.add(getName() + "(arg|arg., key.) - encrypt a string or stem of them. If the key is symmetric, do symmetric encryption, otherwise encrypt with the private key"); break; case 3: - dd.add(getName() + "(key., arg|arg., use_private) - encrypt a string or stem of them with the private key if use_private is true"); + dd.add(getName() + "(arg|arg., key., use_private) - encrypt a string or stem of them with the private key if use_private is true"); dd.add(" or use the public key if false. Default is true"); break; } dd.add("key. - the RSA or symmetric key to use. N.B. Elliptic keys are not supported at this time."); dd.add("arg|arg. - a string or a stem of strings"); if (argCount == 3) { - dd.add("use_private - use the private key (if true, this is the default) and the public key if false"); } dd.add("NOTE: You can only encrypt a string with an RSA key that has fewer bits than the key."); @@ -705,16 +744,16 @@ public List getDocumentation(int argCount) { dd.add("One final reminder is that if encrypt/decrypt with one key and decrypt/encrypt with the" + "\nother or you will get an error"); dd.add("E.g."); - dd.add(" " + getName() + "(key., 'marizy doats')"); + dd.add(" " + getName() + "('marizy doats', key.)"); dd.add("(whole bunch of base 64 stuff that depends on the key)"); dd.add("Since this was encrypted with the private key, you would need to specify using the"); dd.add("public key in " + DECRYPT_NAME + " (which is, incidentally, the default there)."); dd.add("\nE.g. Symmetric example"); dd.add("Here, a symmetric key (AES) is created and used."); dd.add(" aes. := crypto#create_key({'type':'AES','alg':'A256GCM','length':512})\n" + - " crypto#encrypt(aes., 'woof woof woof') \n" + + " crypto#encrypt('woof woof woof', aes.) \n" + "67dmKZ6lqHwSt-mIZGs\n" + - " crypto#decrypt(aes., '67dmKZ6lqHwSt-mIZGs')\n" + + " crypto#decrypt('67dmKZ6lqHwSt-mIZGs', aes.)\n" + "woof woof woof\n"); return dd; } @@ -919,28 +958,28 @@ protected QDLStem webKeyToStem(JSONWebKey jsonWebKey) { */ public Object sDeOrEnCrypt(Object[] objects, boolean isEncrypt, String name) { byte[] key = null; - if (objects[0] instanceof QDLStem) { + if (objects[1] instanceof QDLStem) { // check that it is a JWK of type octet - QDLStem sKey = (QDLStem) objects[0]; + QDLStem sKey = (QDLStem) objects[1]; if (sKey.containsKey("kty")) { if (!sKey.getString("kty").equals("oct")) { - throw new BadArgException("Incorrect key type. Must be of type 'oct' (octet-encoded)", 0); + throw new BadArgException("Incorrect key type. Must be of type 'oct' (octet-encoded)", 1); } if (sKey.containsKey("k")) { key = Base64.decodeBase64(sKey.getString("k")); } else { - throw new BadArgException("Incorrect key format: missing 'k' entry for bytes", 0); + throw new BadArgException("Incorrect key format: missing 'k' entry for bytes", 1); } } } else { - if (!(objects[0] instanceof String)) { - throw new BadArgException("the first argument to " + name + " must be a base64 encoded key", 0); + if (!(objects[1] instanceof String)) { + throw new BadArgException("the first argument to " + name + " must be a base64 encoded key", 1); } - key = Base64.decodeBase64((String) objects[0]); + key = Base64.decodeBase64((String) objects[1]); } ProcessSymmetricDeorEncrypt processSymmetricDeorEncrypt = new ProcessSymmetricDeorEncrypt(key, isEncrypt); - return QDLAggregateUtil.process(objects[1], processSymmetricDeorEncrypt); + return QDLAggregateUtil.process(objects[0], processSymmetricDeorEncrypt); } protected class ProcessSymmetricDeorEncrypt extends ProcessScalarImpl { @@ -1059,6 +1098,7 @@ protected QDLStem certToStem(X509Certificate x509Certificate) { QDLStem subject = new QDLStem(); subject.put("x500", x509Certificate.getSubjectX500Principal().getName()); subject.put("dn", x509Certificate.getSubjectDN().getName()); + try { if (x509Certificate.getSubjectAlternativeNames() != null) { QDLStem altNames = processAltNames(x509Certificate.getSubjectAlternativeNames()); @@ -1077,6 +1117,7 @@ protected QDLStem certToStem(X509Certificate x509Certificate) { for (String x : x509Certificate.getNonCriticalExtensionOIDs()) { noncriticalOIDS.getQDLList().add(x); } + QDLStem oids = new QDLStem(); oids.put("critical", criticalOIDS); oids.put("noncritical", noncriticalOIDS); @@ -1236,50 +1277,39 @@ public int[] getArgCount() { public Object evaluate(Object[] objects, State state) throws Throwable { QDLStem certStem = (QDLStem) objects[0]; if (!certStem.containsKey("encoded")) { - throw new IllegalStateException("certs must contain encoded key"); + throw new BadArgException("certs must contain 'encoded' key", 0); } String cert = certStem.getString("encoded"); X509Certificate[] certs = CertUtil.fromX509PEM(cert); - // better be one? - boolean isScalar = false; - String oid = null; - QDLStem oidStem = null; - if (objects[1] instanceof String) { - oid = (String) objects[1]; - isScalar = true; - } else { - if (objects[1] instanceof QDLStem) { - oidStem = (QDLStem) objects[1]; - } else { - throw new BadArgException(getName() + "requires a string or stem as the second argument", 0); - } + ProcessOIDS processOIDS = new ProcessOIDS(certs[0]); + return QDLAggregateUtil.process(objects[1], processOIDS); + } + + protected class ProcessOIDS extends ProcessScalarImpl{ + public ProcessOIDS(X509Certificate x509Certificate) { + this.x509Certificate = x509Certificate; } - X509Certificate x509Certificate = certs[0]; - QDLStem outStem = new QDLStem(); - if (isScalar) { - byte[] bb = x509Certificate.getExtensionValue(oid); - if (bb == null) { - return QDLNull.getInstance(); - } + + X509Certificate x509Certificate; + @Override + public Object getDefaultValue(Object value) { + return QDLNull.getInstance(); + } + + @Override + public Object process(String oidKey) { + byte[] bb = x509Certificate.getExtensionValue(oidKey); + if(bb == null){ + return QDLNull.getInstance(); + } return Base64.encodeBase64URLSafeString(bb); } - for (Object key : oidStem.keySet()) { - String oidKey; - byte[] bb; - if (key instanceof Long) { - oidKey = oidStem.getString((Long) key); - } else { - oidKey = oidStem.getString((String) key); - } - bb = x509Certificate.getExtensionValue(oidKey); - if (bb == null) { - outStem.putLongOrString(key, QDLNull.getInstance()); - } else { - outStem.putLongOrString(key, Base64.encodeBase64URLSafeString(bb)); - } + + @Override + public Object process(Object key, String oidKey) { + return process(oidKey); } - return outStem; } @Override @@ -1287,13 +1317,12 @@ public List getDocumentation(int argCount) { List dd = new ArrayList<>(); dd.add(getName() + "(cert., oid | oids.) - get the given OIDs from a given cert."); dd.add("cert. - a single X509 certificate to be probed."); - dd.add(" oid - a string that is the oid (object id), e.g. '2.5.29.15'"); + dd.add(" oid - a string or (set of such strings) that is the oid (object id), e.g. '2.5.29.15'"); dd.add("oids. - a stem of oids whose keys are the return values. Only string-valued OIDs are supported."); - dd.add("You pass in either an oid or stem of them"); dd.add("This returns the base 64 encoded octet stream. Best we can do in general..."); dd.add("If there is no such value, a null is returned."); dd.add("An OID (object identifier) is a bit of X 509 voodoo that allows for"); - dd.add("addressing attributes. These are very specific and not standardizes, hence are"); + dd.add("addressing attributes. These are very specific and not standardized, hence are"); dd.add("bona fide low-level operations, but often the only way to get certain custom values"); dd.add("E.g. to get the EPPN (if present) from a cert"); dd.add(" " + getName() + "(cert., {'eppn':'1.3.6.1.4.1.5923.1.1.1.6'}"); diff --git a/language/src/main/java/org/qdl_lang/extensions/crypto/CryptoModule.java b/language/src/main/java/org/qdl_lang/extensions/crypto/CryptoModule.java index 102be0af6..1d51d117f 100644 --- a/language/src/main/java/org/qdl_lang/extensions/crypto/CryptoModule.java +++ b/language/src/main/java/org/qdl_lang/extensions/crypto/CryptoModule.java @@ -2,6 +2,7 @@ import org.qdl_lang.extensions.JavaModule; import org.qdl_lang.extensions.QDLFunction; +import org.qdl_lang.extensions.QDLVariable; import org.qdl_lang.module.Module; import org.qdl_lang.state.State; @@ -40,6 +41,9 @@ public Module newInstance(State state) { funcs.add(crypto.new FromJWT()); funcs.add(crypto.new VerifyJWT()); cryptoModule.addFunctions(funcs); + ArrayList vars = new ArrayList<>(); + vars.add(crypto.new KeyType()); + cryptoModule.addVariables(vars); if (state != null) { cryptoModule.init(state); } diff --git a/tests/src/test/java/org/qdl_lang/CryptoTest.java b/tests/src/test/java/org/qdl_lang/CryptoTest.java new file mode 100644 index 000000000..b7e13f771 --- /dev/null +++ b/tests/src/test/java/org/qdl_lang/CryptoTest.java @@ -0,0 +1,202 @@ +package org.qdl_lang; + +import edu.uiuc.ncsa.security.core.util.DebugUtil; +import org.qdl_lang.extensions.crypto.Crypto; +import org.qdl_lang.parsing.QDLInterpreter; +import org.qdl_lang.state.State; + +public class CryptoTest extends AbstractQDLTester { + /* + These files contain QDl scripts that just return the keys. This is so the test for + importing them is a separate test. + */ + String EC_PUBLIC_KEY = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/ec_public.qdl"; + String EC_KEY = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/ec.qdl"; + String RSA_KEY = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/rsa.qdl"; + String RSA_PUBLIC_KEY = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/rsa_public.qdl"; + String AES_KEY = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/aes.qdl"; + /* + These are test items in PEM format to check reading, import, etc. + */ + String TEST_CERT = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/github.pem"; + String TEST_PKCS1 = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/pkcs1.pem"; + String TEST_PKCS8 = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/pkcs8.pem"; + String TEST_PKCS8_PUBLIC = DebugUtil.getDevPath() + "/qdl/tests/src/test/resources/crypto/pkcs8_public.pem"; + + public void testSymmetricEncryption() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "aes. := script_load('" + AES_KEY + "');"); + addLine(script, "c := j_load('crypto');"); + addLine(script, "test_string := 'woof woof woof';"); + addLine(script, "encrypted_string := 'LXwYRcBgwmIpFUtAF10';"); + addLine(script, "test_set := {'arf',42,{'fnord'}};"); + addLine(script, "encrypted_set := {{'PH0YUYQ'},'O2ER',42};"); + addLine(script, "encrypt_string_ok := c#encrypt(test_string, aes.) == encrypted_string;"); + addLine(script, "decrypt_string_ok := c#decrypt(encrypted_string, aes.) == test_string;"); + addLine(script, "encrypt_set_ok := c#encrypt(test_set, aes.) == encrypted_set;"); + addLine(script, "decrypt_set_ok := c#decrypt(encrypted_set, aes.) == test_set;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("encrypt_string_ok", state) : "symmetric encryption for string failed"; + assert getBooleanValue("decrypt_string_ok", state) : "symmetric decryption for string failed"; + assert getBooleanValue("encrypt_set_ok", state) : "symmetric encryption for set failed"; + assert getBooleanValue("decrypt_set_ok", state) : "symmetric decryption for set failed"; + } + + public void testRSAEncryption() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "rsa. := script_load('" + RSA_KEY + "');"); + addLine(script, "c := j_load('crypto');"); + addLine(script, "test_string := 'woof woof woof';"); + addLine(script, "encrypted_string := 'FWSjwdYsxmoZK0fHjb7pzo0y0_Cw1VDUNC4_LIpJRqJP3uwDbA6z2_8SE72Tn70cOFzLP45Ydhj4Fetbyz6EV6P-S4-FX5Kqj0KlR37FEQ3IlPs3boemZfn8RpBUQ5zZDTwRLjeDLG34iL1hk3bC2JLefFxzCbvVgK0EnMpCa7PGdsHAbcu_2mm4rw8uNrCAzFaNUBRZ_LYVnP2PwzM34Pl09OEr4E10q41YpXeNMSexxJzfUnkubmxNaTomY_iETElgrtOLeNcf8k-tGP9P9_zB7fgvE4ujJJCT3mvT0Fl1EhHa0ji2vN7vsiu2L8Qmh2SNNOHiUZoGoySNzMMWkw';"); + addLine(script, "test_set := {'arf',42,{'fnord'}};"); + addLine(script, "encrypted_set := {'D9aV2v7iXkdaHUcxmREh2btp35mFiiZpgdhK_CqMG46PNM2RATwZIUJMv1KvxIPmZwu0H2Fx1y-wBAEqeqVG0gopvk-Ts3MbsIwdt6Bq_znN54gPzZJSIp9jbwdiqM1HOkipAnwjTlA5WQ-glFgs_bFl-yHaIifnDtvRBDWoRYbOQGvAuo_HDi40_FT7xSYV-haRO4ofqINMnz-geeVt-KnSEvv_43pqDLLlOBTwdeLvkFJ4OASQ3jY6bKM4NmgAD-2ne9jgH2so7JgoFugWVQhIi2Jpjr2zr3Aw6RfAUCjbOdmxYFxwr0FIoxTUKuS38Pv9iociKZ2hobxgJDH7hA',{'ZBPnmBx8bC1Dwm8YcbCrkTRat14RdUDWsw7UDtBLYH1JuCxkdSqqb7nicyMVIFMvkv5T21dLSCtdQxfkoHFSEmWlPtW6KISdXQPVSHILehhvWYKAAZ52d7kbIgRmJnAsrL_3DvnRX05sGuWRIAQ3dQH3h4P0OliT7b-GvhPVEe6Wjxyi6LQnH3gcK2SbkQ5OyQtvkVNVVOt8ZZrPtemPc3jehNcgHX_U19ORVNmYajj9awxX_C32QsTAl6QveQaA-4_UmCVkDzZZRL66liaAjPo9hSbLChoADvSEDRLi96IJd2FW_J0M0qX_DghsHy0mS0qCehgpI54XOnwIdzz7EA'},42};"); + addLine(script, "encrypt_string_ok := c#encrypt(test_string, rsa.) == encrypted_string;"); + addLine(script, "decrypt_string_ok := c#decrypt(encrypted_string, rsa.) == test_string;"); + addLine(script, "encrypt_set_ok := c#encrypt(test_set, rsa.) == encrypted_set;"); + addLine(script, "decrypt_set_ok := c#decrypt(encrypted_set, rsa.) == test_set;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("encrypt_string_ok", state) : "RSA encryption for string failed"; + assert getBooleanValue("decrypt_string_ok", state) : "RSA decryption for string failed"; + assert getBooleanValue("encrypt_set_ok", state) : "RSA encryption for set failed"; + assert getBooleanValue("decrypt_set_ok", state) : "RSA decryption for set failed"; + } + + public void testToPublic() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "rsa. := script_load('" + RSA_KEY + "');"); + addLine(script, "rsa_public. := script_load('" + RSA_PUBLIC_KEY + "');"); + addLine(script, "ec. := script_load('" + EC_KEY + "');"); + addLine(script, "ec_public. := script_load('" + EC_PUBLIC_KEY + "');"); + addLine(script, "aes. := script_load('" + AES_KEY + "');"); + addLine(script, "c := j_load('crypto');"); + addLine(script, "rsa_ok := false ∉ (c#to_public(rsa.) == rsa_public.);"); + addLine(script, "ec_ok := false ∉ (c#to_public(ec.) == ec_public.);"); + addLine(script, "aes_ok := false ∉ (c#to_public(aes.) == aes.);"); // symmetric key is public + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("rsa_ok", state) : "convert RSA to public key failed"; + assert getBooleanValue("ec_ok", state) : "convert EC to public key failed"; + assert getBooleanValue("aes_ok", state) : "convert AES to public key failed"; + } + + public void testJWTRSA() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "rsa. := script_load('" + RSA_KEY + "');"); + addLine(script, "c := j_load('crypto');"); + addLine(script, "test. := {'A':'p','B':{'integer':42},'C':3.1415};"); + addLine(script, "jwt := c#to_jwt(test., rsa.);"); + addLine(script, "verified := c#verify(jwt, rsa.);"); + addLine(script, "payload. := c#from_jwt(jwt);"); + addLine(script, "ok := false ∉ test. == payload.;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("verified", state) : "JWT with RSA verified failed"; + assert getBooleanValue("ok", state) : "JWT payload failed"; + } + + public void testJWTEC() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "ec. := script_load('" + EC_KEY + "');"); + addLine(script, "c := j_load('crypto');"); + addLine(script, "test. := {'A':'p','B':{'integer':42},'C':3.1415};"); + addLine(script, "jwt := c#to_jwt(test., ec.);"); + addLine(script, "verified := c#verify(jwt, ec.);"); + addLine(script, "payload. := c#from_jwt(jwt);"); + addLine(script, "ok := false ∉ test. == payload.;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("verified", state) : "JWT with EC key verified failed"; + assert getBooleanValue("ok", state) : "JWT payload failed"; + } + + public void testReadCert() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "c := j_load('crypto');"); + addLine(script, "git. := c#read_x509('" + TEST_CERT + "');"); + addLine(script, "alg_ok := git.'algorithm'.'name' == 'SHA256withECDSA';"); + addLine(script, "iss_ok := git.'issuer'.'alt_names'.'dNSName' == 'www.github.com';"); + addLine(script, "expires_at_ok := git.'not_after' == 1741391999000;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("alg_ok", state) : "JWT with EC key verified failed"; + assert getBooleanValue("iss_ok", state) : "JWT with EC key verified failed"; + assert getBooleanValue("expires_at_ok", state) : "JWT with EC key verified failed"; + } + public void testReadCertOIDs() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "c := j_load('crypto');"); + addLine(script, "git. := c#read_x509('" + TEST_CERT + "');"); + addLine(script, "critical. :=['BAQDAgeA','BAIwAA'];"); + addLine(script, "noncritical. :=['BIIBcASCAWwBagB3AM8RVu7VLnyv84db2Wkum-kacWdKsBfsrAHSW3fOzDsIAAABjhY68BkAAAQDAEgwRgIhAPug3P_ag7xUZpZauquwFAHNAfSFGEwubXWh4ymDV81rAiEApZzSrtn6bENVhX_qi_t_-LQf9oBwdIIiL9AlwQKto6kAdgCi4wrkRe-9rZt-OO1HZ3dT14JbhJTXK14bLMS5UKRH5wAAAY4WOu_4AAAEAwBHMEUCIQDK6kQhUAyTRzwFVWkXRBuKx-gTDLnElApA57wS8xThbwIgYAgi7OPEEWUemSpyxrtRnLbjL8HrFmeS1TD817mrmEIAdwBOdaMnXJoQwzhbbNTfP1LrHfDgjhuNacCx-mSxYpo53wAAAY4WOu_3AAAEAwBIMEYCIQD7w69DOmBF_fW4sGwITyS0JR--yJFPvNZKp5eWIDT1NQIhANwHtef3toQMwEpcht2bkpn0aO9HKgX2yQPn_gad6gxb','BHgwdjBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvRUNDRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20'," + + "'BBYEFDtoPzQ69Uc0yu-mTj2avV5uesyf'," + + "'BB4wHIIKZ2l0aHViLmNvbYIOd3d3LmdpdGh1Yi5jb20'," + + "'BEIwQDA0BgsrBgEEAbIxAQICBzAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgE'," + + "'BBgwFoAU9oUKOxGG4QR9DqoLLNLuzGR7e64'," + + "'BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC'];"); + addLine(script, "read_critical. := c#read_oid(git., git.'oids'.'critical');"); + addLine(script, "c_count_ok := size(critical.) == size(read_critical.);"); + addLine(script, "critical_ok := false ∉ read_critical. == critical.;"); + + addLine(script, "read_noncritical. ≔ c#read_oid(git., git.'oids'.'noncritical');"); + addLine(script, "nonc_count_ok := size(noncritical.) == size(read_noncritical.);"); + addLine(script, "noncritical_ok := false ∉ read_noncritical. == noncritical.;"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("c_count_ok", state) : "missing critical OIDs"; + assert getBooleanValue("critical_ok", state) : "incorrect critical OIDs"; + assert getBooleanValue("nonc_count_ok", state) : "missing noncritical OIDs"; + assert getBooleanValue("noncritical_ok", state) : "incorrect noncritical OIDs"; + } + public void testReadPKCS1() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "c := j_load('crypto');"); + addLine(script, "pkcs1. := c#import('" + TEST_PKCS1 + "', '" + Crypto.PKCS_1_TYPE + "');"); + // testing whole thing is messy, so we test parts that must work. + addLine(script, "dp_ok := pkcs1.'dp' == 'zhnLPN9F1Lqj-rWPry2fjfDulOpXCc4Q5NSlhvoYIxAoI0K7uaP4oGfRfHAFFCP4Q0NTpHIaFUNpf0ZiHfpz1hIaLHoClRGfw9J3elBImbYBdbVh5BIKZQ3QQl4lrXun3MlStoq5KILrgjby5SCqQtCrX7r_HvdBSmeixzbj0AU';"); + addLine(script, "e_ok := pkcs1.'e' == 'AQAB';"); + addLine(script, "q_ok := pkcs1.'q' == 'xwb2ZPwgCDVUSBYZxZdbrVOujrkW2Uk4KE7KVKMWLpDaCK2-c_LYXbsAJJ6JRecy-36XCUBgbzhFnFMdpoz9zOQ4_-t9DLvspwjy7jjLoSNAeUm26jTNVi5rNdySWJLdM0g5hPEOdbxSy8FrSaSfKKYca3DKeFPz1QCBg0jd_NE';"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("dp_ok", state) : "PKCS1 import key failed dp"; + assert getBooleanValue("e_ok", state) : "PKCS1 import key failed e"; + assert getBooleanValue("q_ok", state) : "PKCS1 import key failed q"; + } + public void testReadPKCS8() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "c := j_load('crypto');"); + addLine(script, "pkcs8. := c#import('" + TEST_PKCS8 + "', '" + Crypto.PKCS_8_TYPE + "');"); + // testing whole thing is messy, so we test parts that must work. + addLine(script, "dp_ok := pkcs8.'dp' == 'Q1E8HMJjtSp_vpg8Dgu8jLVBSWcpQ9wBjKaiYhC85BmNRTsE8QWLuIwUWam5lWqAdbM4Q31-ZKtj8cr4quD80ugx2Y_8c43N4-3MVErALf1agFZ52uZbkJSHJ7EytRaMbmy3cJ2raZ3ssd_-2AyBGHTbSsyzW2nnmHGycOSZm6E';"); + addLine(script, "e_ok := pkcs8.'e' == 'AQAB';"); + addLine(script, "q_ok := pkcs8.'q' == 'um0SMkYShdxFHLHWV1J9KqHpYH2kYx13lNhSRfspRKwjfsNyQWyIAAOdL8tW_O7458r9efkDv0MGR2I64nz2kdXMO7t3NLy2zP3HMVXws3HKjODiHD-3ebo6hxWLAiBqZ3KRsZChMzBPjK5bcXZdE7joGrmMOc2FbG7dSghfVwc';"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("dp_ok", state) : "PKCS8 import key failed dp"; + assert getBooleanValue("e_ok", state) : "PKCS8 import key failed e"; + assert getBooleanValue("q_ok", state) : "PKCS8 import key failed q"; + } + public void testReadPKCS8Public() throws Throwable { + StringBuffer script = new StringBuffer(); + addLine(script, "c := j_load('crypto');"); + addLine(script, "pkcs8. := c#import('" + TEST_PKCS8_PUBLIC + "', '" + Crypto.PKCS_8_PUBLIC_TYPE + "');"); + // testing whole thing is messy, so we test parts that must work. + addLine(script, "n_ok := 'jn-jMHBqZoAsQ9EkBd4iwx9QckvJe1gUf9K_0iH37fHypqXkxSnITv4Hw4P-HZTWa94Re9ZLv223LJETEOoc5inK-rm1h-R5UVvJIWz7HU' < pkcs8.'n';"); + addLine(script, "e_ok := pkcs8.'e' == 'AQAB';"); + State state = testUtils.getNewState(); + QDLInterpreter interpreter = new QDLInterpreter(null, state); + interpreter.execute(script.toString()); + assert getBooleanValue("n_ok", state) : "PKCS8 public key import failed n"; + assert getBooleanValue("e_ok", state) : "PKCS8 public key import failed e"; + } +} diff --git a/tests/src/test/java/org/qdl_lang/TestSuite.java b/tests/src/test/java/org/qdl_lang/TestSuite.java index 41f61e273..c82cfcfcb 100644 --- a/tests/src/test/java/org/qdl_lang/TestSuite.java +++ b/tests/src/test/java/org/qdl_lang/TestSuite.java @@ -26,10 +26,11 @@ OldModuleTests.class, GlomTest.class, SerializationTest.class, - // Without the VFS tests, all other tests (156 of them) take 1.532 s. (av. 9.82 ms per test) - // Running this next test adds a full 3 seconds for the initial database connection - // and unzipping. - // Point is that this is quite fast since pretty much every test creates a parser and executes it. + CryptoTest.class, + // Without the VFS tests, all other tests (569 of them, often with multiple parts, 1/1/2025) takes 6.559 s. + // (av. 11.6 ms per test) + // Running this next test adds up to several seconds for the initial database latency, + // Point is that QDL is actually quite fast since pretty much every test creates a parser and executes it. VFSTest.class }) diff --git a/tests/src/test/resources/crypto/aes.qdl b/tests/src/test/resources/crypto/aes.qdl new file mode 100644 index 000000000..2264845c4 --- /dev/null +++ b/tests/src/test/resources/crypto/aes.qdl @@ -0,0 +1,10 @@ +/* + AES (symmetric) key used for testing the cryptography module +*/ +return( +{ + 'k':'WhN3I-AXrQ1PNTwveDsB-eLR74HGDkC6_O5OmjBDBbrMejkTHpPPmRmlg9zwcW80FDS_sgPLU5ZFrU8WZLH1J_vvf8drILidqc2_Jyt5QteXYI1bxP82zVGGdOWDECKmHCQq0-D3PKcHeLJrpbPEKU7BklKayY9v-b9GhKdnhUeIzWkeq3ol-12PpVMk7hPsjpxbpFecqez6mVLiZBmbifaC0j4xv13WS1HQ2GbgFQN11MJRfhk63n0JxMZ1IlluTGW4rNNqL51d6Np9vLgQ9AaU49R6QFMx2VDxt3WXkpcqnQzctlmOtdpKdmEzrTZH06sL1Xda62KOZEwK6Detfg', + 'kid':'16776DE0877FFE3B', + 'kty':'oct' + } + ); diff --git a/tests/src/test/resources/crypto/ec.qdl b/tests/src/test/resources/crypto/ec.qdl new file mode 100644 index 000000000..213090cca --- /dev/null +++ b/tests/src/test/resources/crypto/ec.qdl @@ -0,0 +1,15 @@ +/* + Elliptic curve key used for testing the cryptography module +*/ +return( + {'alg':'ES256', + 'crv':'P-256', + 'd':'fOuEaM72yugYAlO14f5bj_aZO5S6h2nfVOAhzkxrbbI', + 'iat':1735649982, + 'kid':'D57E9C2511070859', + 'kty':'EC', + 'use':'sig', + 'x':'kTz5JR4GN26jBnXlTpcs3yYw1jirl6aF0YkZNNXoW24', + 'y':'uFtnSWEy1D1-iUNZXXYhNhBoufiR5U2iY95e7dV1JOY' + } +); diff --git a/tests/src/test/resources/crypto/ec_public.qdl b/tests/src/test/resources/crypto/ec_public.qdl new file mode 100644 index 000000000..1da648144 --- /dev/null +++ b/tests/src/test/resources/crypto/ec_public.qdl @@ -0,0 +1,10 @@ +return( +{ + 'alg':'ES256', + 'kid':'D57E9C2511070859', + 'kty':'EC', + 'use':'sig', + 'x':'AJE8-SUeBjduowZ15U6XLN8mMNY4q5emhdGJGTTV6Ftu', + 'y':'ALhbZ0lhMtQ9folDWV12ITYQaLn4keVNomPeXu3VdSTm' + } +); \ No newline at end of file diff --git a/tests/src/test/resources/crypto/github.pem b/tests/src/test/resources/crypto/github.pem new file mode 100644 index 000000000..7c41370ce --- /dev/null +++ b/tests/src/test/resources/crypto/github.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEozCCBEmgAwIBAgIQTij3hrZsGjuULNLEDrdCpTAKBggqhkjOPQQDAjCBjzEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5T +ZWN0aWdvIEVDQyBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMB4X +DTI0MDMwNzAwMDAwMFoXDTI1MDMwNzIzNTk1OVowFTETMBEGA1UEAxMKZ2l0aHVi +LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABARO/Ho9XdkY1qh9mAgjOUkW +mXTb05jgRulKciMVBuKB3ZHexvCdyoiCRHEMBfFXoZhWkQVMogNLo/lW215X3pGj +ggL+MIIC+jAfBgNVHSMEGDAWgBT2hQo7EYbhBH0Oqgss0u7MZHt7rjAdBgNVHQ4E +FgQUO2g/NDr1RzTK76ZOPZq9Xm56zJ8wDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB +/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAw +NAYLKwYBBAGyMQECAgcwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNv +bS9DUFMwCAYGZ4EMAQIBMIGEBggrBgEFBQcBAQR4MHYwTwYIKwYBBQUHMAKGQ2h0 +dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb0VDQ0RvbWFpblZhbGlkYXRpb25T +ZWN1cmVTZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3Rp +Z28uY29tMIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwDPEVbu1S58r/OHW9lp +LpvpGnFnSrAX7KwB0lt3zsw7CAAAAY4WOvAZAAAEAwBIMEYCIQD7oNz/2oO8VGaW +WrqrsBQBzQH0hRhMLm11oeMpg1fNawIhAKWc0q7Z+mxDVYV/6ov7f/i0H/aAcHSC +Ii/QJcECraOpAHYAouMK5EXvva2bfjjtR2d3U9eCW4SU1yteGyzEuVCkR+cAAAGO +Fjrv+AAABAMARzBFAiEAyupEIVAMk0c8BVVpF0QbisfoEwy5xJQKQOe8EvMU4W8C +IGAIIuzjxBFlHpkqcsa7UZy24y/B6xZnktUw/Ne5q5hCAHcATnWjJ1yaEMM4W2zU +3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGOFjrv9wAABAMASDBGAiEA+8OvQzpgRf31 +uLBsCE8ktCUfvsiRT7zWSqeXliA09TUCIQDcB7Xn97aEDMBKXIbdm5KZ9GjvRyoF +9skD5/4GneoMWzAlBgNVHREEHjAcggpnaXRodWIuY29tgg53d3cuZ2l0aHViLmNv +bTAKBggqhkjOPQQDAgNIADBFAiEAru2McPr0eNwcWNuDEY0a/rGzXRfRrm+6XfZe +SzhYZewCIBq4TUEBCgapv7xvAtRKdVdi/b4m36Uyej1ggyJsiesA +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/src/test/resources/crypto/pkcs1.pem b/tests/src/test/resources/crypto/pkcs1.pem new file mode 100644 index 000000000..7ddb5a77a --- /dev/null +++ b/tests/src/test/resources/crypto/pkcs1.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEApWgvEY7U9ha0beYJOw+uH3UQx6NEl+LQdFMJ3z/mhNwnjtMS +i3gcDoFEg1vWWPPfKH5WpJ8KWzSG2safh9VS+jFOveGVkkNf/3EEj4ThTb8//VCW +NhyCSUv6FBfxElKir9FawGsXdUc6u/tpJfUW4oVLyPGe0t6sBYfHNscUEw0iLifP +YttwPvZsv5bEzmns7NPhdJtpfVSAsvYs4scqY+ekEdvw6H/CMQXUkh23lfJBGZ52 +HiX9m4XOiuA5IUiGeIHSY8FTMpxlZGbEFQCJ6ejfmrDMVNgjpkyKtGLN22RDmMJr +F5ieaVkJ4vm4l7175IFovVGywQ/8Q7RsvmpZjQIDAQABAoIBAAacfPEjN+DkNG8G +GE1biZapS7PnEzlM8A8OOKFLQRADarNbPW0Ern5n7VCgzZb9nGhWcGkhED1oApHh +CYRY4vmsGd0eFKfleINRxaBk68p7P/gEjhR4nD6IwmSmNlUIp4cGg62YOjZOVAsq +d9/0BWelc0uDWNlN3CtWa4CFgYhnWAZdyOd0qr2BgoHS/ARz1KYiXwvB9M8gn3TY +apeUE6K8taGJowHvs9SrtBmVHODCs5DrQdPCMs+nOC6W0YhtZN9Wj9WMfa9VnOxH +EPaDYXmHhNOfIWKfYPCHz0d2yi79vkmBWitGxUZU59uEnKCk5hncNR+0/NZEOygI +5ILA9qECgYEA1MF5519lPVA3w67ENSravE2mA5vN//KwJswRtVw2KrQWnGSgZCEf +YIPx9/MSB3bKL4HVEiwyRb2yEOk8LxFLO66g9NwEC3PfQ2zl6PVWk/TVzwTNBnSZ +uX3du+t/9tgMlSb8izOXo/NSjNvg//Qw3qDTbJ7BhN7cAIk3c66TT/0CgYEAxwb2 +ZPwgCDVUSBYZxZdbrVOujrkW2Uk4KE7KVKMWLpDaCK2+c/LYXbsAJJ6JRecy+36X +CUBgbzhFnFMdpoz9zOQ4/+t9DLvspwjy7jjLoSNAeUm26jTNVi5rNdySWJLdM0g5 +hPEOdbxSy8FrSaSfKKYca3DKeFPz1QCBg0jd/NECgYEAzhnLPN9F1Lqj+rWPry2f +jfDulOpXCc4Q5NSlhvoYIxAoI0K7uaP4oGfRfHAFFCP4Q0NTpHIaFUNpf0ZiHfpz +1hIaLHoClRGfw9J3elBImbYBdbVh5BIKZQ3QQl4lrXun3MlStoq5KILrgjby5SCq +QtCrX7r/HvdBSmeixzbj0AUCgYEAxL/iRjRkKhkmJ1kJwyZ8r5zhHCBnMQhL5rT1 +GbRbUk9J63hupUr1j7s0Sf8bbyo+YRZkkvW8H1a+oeocjrAkmi8nFf+jEDqamQmk +tdEZpEMoEn7Hv0HRl5etzoItfjg5Sd/lVMHEbKluJBUiTZva5yFHSQModMlxayjj +33fiU3ECgYARCQUzdu+EglaJd+7F4uC1AVrICEVRX1uiHJcZe/b/tPm4z3QV5D5U +vG/5BhSHBxeOv1Ir+DWWo/oYTy2ipHsMBx+0W78zmBnY22bq/sVCaLzvyXXjXIvO +qQ5Ahp6OMvv/MvjHdtMzP0MNCHdpSxjixvkK9dF4MBaN8S7BcNVLjQ== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/tests/src/test/resources/crypto/pkcs1_public.pem b/tests/src/test/resources/crypto/pkcs1_public.pem new file mode 100644 index 000000000..aa6c39805 --- /dev/null +++ b/tests/src/test/resources/crypto/pkcs1_public.pem @@ -0,0 +1,8 @@ +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEApWgvEY7U9ha0beYJOw+uH3UQx6NEl+LQdFMJ3z/mhNwnjtMSi3gc +DoFEg1vWWPPfKH5WpJ8KWzSG2safh9VS+jFOveGVkkNf/3EEj4ThTb8//VCWNhyC +SUv6FBfxElKir9FawGsXdUc6u/tpJfUW4oVLyPGe0t6sBYfHNscUEw0iLifPYttw +PvZsv5bEzmns7NPhdJtpfVSAsvYs4scqY+ekEdvw6H/CMQXUkh23lfJBGZ52HiX9 +m4XOiuA5IUiGeIHSY8FTMpxlZGbEFQCJ6ejfmrDMVNgjpkyKtGLN22RDmMJrF5ie +aVkJ4vm4l7175IFovVGywQ/8Q7RsvmpZjQIDAQAB +-----END RSA PUBLIC KEY----- \ No newline at end of file diff --git a/tests/src/test/resources/crypto/pkcs8.pem b/tests/src/test/resources/crypto/pkcs8.pem new file mode 100644 index 000000000..80c5bfd7c --- /dev/null +++ b/tests/src/test/resources/crypto/pkcs8.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOf6MwcGpmgCxD +0SQF3iLDH1ByS8l7WBR/0r/SIfft8fKmpeTFKchO/gfDg/4dlNZr3hF71ku/bbcs +kRMQ6hzmKcr6ubWH5HlRW8khbPsdT/6HFse8lODXzAZvZT+EHvE4BIYVKhFBWSJO +qQ75dSybdiTd11BWyoBbLctH4y3IwWkZARvKMX3mitD+hFn/cSVJFtP1URmv1dbW +s/4DrB2+M6KBlMMIbUOA43VP+UwDmQWCnixUrBlVL//WLWKrWo3Oknu4SrIopKBr +fcl32IVn+v84zB0AAB8ZeZ1DJB37DaHC10CLfHontmR3oBz9IB57UpHNl/YE/GyB +pnL/My43AgMBAAECggEALlwdMfGo1B8oB4o/r38FDTkfWYgJjUzrImjkyk8N08Zu +3MPFCVYeGoDv8q57GpGlLuPJCWJ/M1DVErVCIDMiYsk/BdIsWoE87PixF2RW0EMJ +ulZxdgtzmRGCGHS2tNvCO6jRHIqaoYmHrVK4EfWKpStLNDdMJmhsWP2tkH47E4BI +yhVcRbNRBmk3X+I9yuEFuVSYUU6URkiaUZdczClQeabhvBlrHZqHeS4qyfRzWn77 +PSXlLnpKVGcx7h4gqtxM6IZpmWjSrzM3kX7pPHFR+9xRNrUS5VY7hx7a6BjdeWKP +mETJFcYlC2vMhp30YNiiNF26yd6l2uJB6HK0JSSM0QKBgQDDrclWzMvVA5NfOBlS +6J3JvuSTKQUwc/gDi3IfDlzvbWfKIyIKnFaLqKu/B7CZYOAv0mB/yBDrjzAiUuqP +lf2L1OgbdBbXFL/1DPhHqNkETzcLHakKJ0T0n7AFXQVodBs3ci4Rucighfb1oThj +JAHIP6DMp5KLFcRNOcg12uvzUQKBgQC6bRIyRhKF3EUcsdZXUn0qoelgfaRjHXeU +2FJF+ylErCN+w3JBbIgAA50vy1b87vjnyv15+QO/QwZHYjrifPaR1cw7u3c0vLbM +/ccxVfCzccqM4OIcP7d5ujqHFYsCIGpncpGxkKEzME+Mrltxdl0TuOgauYw5zYVs +bt1KCF9XBwKBgENRPBzCY7Uqf76YPA4LvIy1QUlnKUPcAYymomIQvOQZjUU7BPEF +i7iMFFmpuZVqgHWzOEN9fmSrY/HK+Krg/NLoMdmP/HONzePtzFRKwC39WoBWedrm +W5CUhyexMrUWjG5st3Cdq2md7LHf/tgMgRh020rMs1tp55hxsnDkmZuhAoGBAJJd +nBG4jkZmoCRdQ4mfjAHyyQYm3u+qbP6BsGadQNNXyy51SLkw+r34GGsz3IINJYLn +Doe7CEQb3UwiRVUZA4WQNB8Zmgffui3LeZ60eJyKVJqy3ROMuwJpQhZYxaDPznqV +qumcQdOstGghZE36vi0D2cdRslSXlY+Co17CoAf1AoGAQ3Mj3B/8NlT9pAXRgHhB +Il6Inm/OP0Lz7bbGN/oL4heZr6/xzG3psCNNDvrXhae1vEU+BUr1QKZEwGXctaxX +mtjgp37KiMtwOcH+kJrnYrkGDjT3zdFH30vqZmUQZLIyiisIclxiWTwjPE2AQfWt +wlUWlxIUlMpkoVsmja7NSa8= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/src/test/resources/crypto/pkcs8_public.pem b/tests/src/test/resources/crypto/pkcs8_public.pem new file mode 100644 index 000000000..9064d64eb --- /dev/null +++ b/tests/src/test/resources/crypto/pkcs8_public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjn+jMHBqZoAsQ9EkBd4i +wx9QckvJe1gUf9K/0iH37fHypqXkxSnITv4Hw4P+HZTWa94Re9ZLv223LJETEOoc +5inK+rm1h+R5UVvJIWz7HU/+hxbHvJTg18wGb2U/hB7xOASGFSoRQVkiTqkO+XUs +m3Yk3ddQVsqAWy3LR+MtyMFpGQEbyjF95orQ/oRZ/3ElSRbT9VEZr9XW1rP+A6wd +vjOigZTDCG1DgON1T/lMA5kFgp4sVKwZVS//1i1iq1qNzpJ7uEqyKKSga33Jd9iF +Z/r/OMwdAAAfGXmdQyQd+w2hwtdAi3x6J7Zkd6Ac/SAee1KRzZf2BPxsgaZy/zMu +NwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/tests/src/test/resources/crypto/readme.txt b/tests/src/test/resources/crypto/readme.txt new file mode 100644 index 000000000..ba0d83ef2 --- /dev/null +++ b/tests/src/test/resources/crypto/readme.txt @@ -0,0 +1,4 @@ +This directory has files for testing the QDL cryptography module. +QDL scripts return a fixed key for testing. +There is also the current github public X509 cert in github.pem +Various public and private key formats for PEM are supported \ No newline at end of file diff --git a/tests/src/test/resources/crypto/rsa.qdl b/tests/src/test/resources/crypto/rsa.qdl new file mode 100644 index 000000000..4b593419b --- /dev/null +++ b/tests/src/test/resources/crypto/rsa.qdl @@ -0,0 +1,19 @@ +/* + RSA 2048 bit key used for testing the cryptography module +*/ +return( + {'alg':'RS256', + 'd':'m09jBZ-02WOFbjkzNrxfo-Hnyw6-9lOVIy2sw1x0ZpykpP9YhenLsqjbn4PMf5FHlMIYNevDQ_tnoz00qPK5_aU0PvnVb-I1opiXZDj6D6Pp6EPf_9gukVRhWp7OURov62g7K1Ok9dy-pxGezY7KBhmtcw4DwUf6TyvmI9sU4EdL4SIyThWvBA15w4GMMNJoBUEm81yMbwFB-h6qSzVlqk4O33KDDVAGqAZkVwjaVW2GmjRO4uJ94PCSyjhaTaZ38m1HOuSAeKQ4fpVaIukZqUZ771q49BB6TJosiAN9gzmygws1bZLd_xiJWexqh771ji58RWt7gvsvf0LpevpJJQ', + 'dp':'JTxjy0rRkeKWGhS6arNODbsZ-p_0DIWxeTD9Tg1NIXJuK6yn-kg7LrFnKG3sfYvZXHZ-1aSeht9dbkp2t2J4LD1WKU4rreovS3oWReMucpncGIXqGQMlhkKx1tjsUTk4kQRszWKULRSWkhQjjpoJECe7R9TNU9IrkcPbt5gdKkc', + 'dq':'h_iDE5LBCKDHNjIJRgmuHAgI5wGkbhJTwNincKzOs0LBLvNKtvnCGS3faLhT9bYEp84BLhISVlqf8lSSbgEFE4fBnR0aIvWkotFxE3XQokFsjrtl2ly4MAPGz5ol1vaLkML5mT7JSu4MDceRbl65DyulSWXBfVe2lbbghkgrm70', + 'e':'AQAB', + 'iat':1735649963, + 'kid':'E27317A047F4ABBB', + 'kty':'RSA', + 'n':'p9l1YGCQ7CxBAKpazj0YmaNEiGJaqI-djD-CTZJ7rfQ8TsqQy-2mxDZZgdlFeubKGFCaK_JGxxeGcmqcawoZBMEaOI1smT3J_iBnmcWoviohGzUC5ibxA_5OSfiQyE6XzkmXwDLc1iRVPbda0KlvXUyw-J09aHyiw1urHJkLFl5mP5MBQiuNtSAJ4vBMSfLstkaiMI-fyCMyQ1T6kdm9y5alPu5ix4o-Ia2T_Hz_tdcW7d2flnv6D_Jk3fuR1AidIRi3Vso7Gsc5c_lflMiBBeVYxB3QdR5xopOfWi0HQoCu2DQQ7FAllX2LCTl4GRxdMlqipqVDgHP0rJRn6iex2Q', + 'p':'7QpLosQeQU2bmxzVJBMERyWQ49Mbo3DRpWXwm9QEDAZBv916Cv8EUyr9iLe8cxcfnO20qHs-B3UNytU62udlZepTkTQR5-0IOO3ERSo06Q5QxpVpuvO0V2-UBL5bUC7LHXEQLu60-C-iqv_RHsykeKv2V0iDtUnpqxd8ZKe32Os', + 'q':'tUZkh6OJCDooorHpu3YUgaQkHZfNK9-jccpSDzUwK-s76Ga0WA3g_41PCPyzrRqPqJucczYRhVpy6FluN_2EL0T3XsNTkCMzsaqNMh-fIx76yF8DJOpGvsSoSeminxDgLWdNQIvUWPxWwmQWfIxQMATFyzW01nrmurFyxfVoL0s', + 'qi':'OGJv6iP_WUhDklGrU2f86tc1pfjJpmILZv8W2MfM6uTOR3OcBpUGmW0Lx6k_WprxM1C0J3UIx6iOZ1B7VPu01bGV6JoEuEfycYPsGf7yc1oVAPfdn8pFYzLASzbfIq78X7689xmMLBxuFKB6MFsJBc3ZDfYw1aSGbCpCdMXhbx8', + 'use':'sig' + } + ); diff --git a/tests/src/test/resources/crypto/rsa_public.qdl b/tests/src/test/resources/crypto/rsa_public.qdl new file mode 100644 index 000000000..854a3352e --- /dev/null +++ b/tests/src/test/resources/crypto/rsa_public.qdl @@ -0,0 +1,10 @@ +return( +{ + 'alg':'RS256', + 'e':'AQAB', + 'kid':'E27317A047F4ABBB', + 'kty':'RSA', + 'n':'AKfZdWBgkOwsQQCqWs49GJmjRIhiWqiPnYw_gk2Se630PE7KkMvtpsQ2WYHZRXrmyhhQmivyRscXhnJqnGsKGQTBGjiNbJk9yf4gZ5nFqL4qIRs1AuYm8QP-Tkn4kMhOl85Jl8Ay3NYkVT23WtCpb11MsPidPWh8osNbqxyZCxZeZj-TAUIrjbUgCeLwTEny7LZGojCPn8gjMkNU-pHZvcuWpT7uYseKPiGtk_x8_7XXFu3dn5Z7-g_yZN37kdQInSEYt1bKOxrHOXP5X5TIgQXlWMQd0HUecaKTn1otB0KArtg0EOxQJZV9iwk5eBkcXTJaoqalQ4Bz9KyUZ-onsdk', + 'use':'sig' + } +); \ No newline at end of file