PageRenderTime 24ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jruby-1.7.3/src/org/jruby/ext/openssl/X509Name.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 488 lines | 382 code | 54 blank | 52 comment | 62 complexity | 56ea4a1c9227e7bf86126a050a6cc772 MD5 | raw file
  1. /***** BEGIN LICENSE BLOCK *****
  2. * Version: EPL 1.0/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Common Public
  5. * License Version 1.0 (the "License"); you may not use this file
  6. * except in compliance with the License. You may obtain a copy of
  7. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Software distributed under the License is distributed on an "AS
  10. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11. * implied. See the License for the specific language governing
  12. * rights and limitations under the License.
  13. *
  14. * Copyright (C) 2006, 2007 Ola Bini <ola@ologix.com>
  15. *
  16. * Alternatively, the contents of this file may be used under the terms of
  17. * either of the GNU General Public License Version 2 or later (the "GPL"),
  18. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  19. * in which case the provisions of the GPL or the LGPL are applicable instead
  20. * of those above. If you wish to allow use of your version of this file only
  21. * under the terms of either the GPL or the LGPL, and not to allow others to
  22. * use your version of this file under the terms of the EPL, indicate your
  23. * decision by deleting the provisions above and replace them with the notice
  24. * and other provisions required by the GPL or the LGPL. If you do not delete
  25. * the provisions above, a recipient may use your version of this file under
  26. * the terms of any one of the EPL, the GPL or the LGPL.
  27. ***** END LICENSE BLOCK *****/
  28. package org.jruby.ext.openssl;
  29. import java.io.IOException;
  30. import java.util.ArrayList;
  31. import java.util.Enumeration;
  32. import java.util.Iterator;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.Vector;
  36. import org.bouncycastle.asn1.ASN1Object;
  37. import org.bouncycastle.asn1.ASN1Encodable;
  38. import org.bouncycastle.asn1.ASN1EncodableVector;
  39. import org.bouncycastle.asn1.ASN1Encoding;
  40. import org.bouncycastle.asn1.ASN1InputStream;
  41. import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  42. import org.bouncycastle.asn1.ASN1Sequence;
  43. import org.bouncycastle.asn1.ASN1Set;
  44. import org.bouncycastle.asn1.ASN1Primitive;
  45. import org.bouncycastle.asn1.ASN1String;
  46. import org.bouncycastle.asn1.BERTags;
  47. import org.bouncycastle.asn1.DLSequence;
  48. import org.bouncycastle.asn1.DLSet;
  49. import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
  50. import org.bouncycastle.asn1.x500.RDN;
  51. import org.bouncycastle.asn1.x500.X500Name;
  52. import org.bouncycastle.asn1.x509.X509DefaultEntryConverter;
  53. import org.jruby.Ruby;
  54. import org.jruby.RubyArray;
  55. import org.jruby.RubyClass;
  56. import org.jruby.RubyFixnum;
  57. import org.jruby.RubyHash;
  58. import org.jruby.RubyModule;
  59. import org.jruby.RubyNumeric;
  60. import org.jruby.RubyObject;
  61. import org.jruby.RubyString;
  62. import org.jruby.anno.JRubyMethod;
  63. import org.jruby.exceptions.RaiseException;
  64. import org.jruby.ext.openssl.x509store.Name;
  65. import org.jruby.runtime.ObjectAllocator;
  66. import org.jruby.runtime.ThreadContext;
  67. import org.jruby.runtime.builtin.IRubyObject;
  68. /**
  69. *
  70. * TODO member variables and methods are based on BC X509 way of doing things (now deprecated). Change
  71. * it to do it the X500 way, with RDN and X500NameBuilder.
  72. *
  73. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  74. */
  75. public class X509Name extends RubyObject {
  76. private static final long serialVersionUID = -226196051911335103L;
  77. private static ObjectAllocator X509NAME_ALLOCATOR = new ObjectAllocator() {
  78. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  79. return new X509Name(runtime, klass);
  80. }
  81. };
  82. public static void createX509Name(Ruby runtime, RubyModule mX509) {
  83. RubyClass cX509Name = mX509.defineClassUnder("Name",runtime.getObject(),X509NAME_ALLOCATOR);
  84. RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError");
  85. mX509.defineClassUnder("NameError",openSSLError,openSSLError.getAllocator());
  86. cX509Name.defineAnnotatedMethods(X509Name.class);
  87. cX509Name.setConstant("COMPAT",runtime.newFixnum(COMPAT));
  88. cX509Name.setConstant("RFC2253",runtime.newFixnum(RFC2253));
  89. cX509Name.setConstant("ONELINE",runtime.newFixnum(ONELINE));
  90. cX509Name.setConstant("MULTILINE",runtime.newFixnum(MULTILINE));
  91. cX509Name.setConstant("DEFAULT_OBJECT_TYPE",runtime.newFixnum(BERTags.UTF8_STRING));
  92. RubyHash hash = new RubyHash(runtime, runtime.newFixnum(BERTags.UTF8_STRING));
  93. hash.op_aset(runtime.getCurrentContext(), runtime.newString("C"),runtime.newFixnum(BERTags.PRINTABLE_STRING));
  94. hash.op_aset(runtime.getCurrentContext(), runtime.newString("countryName"),runtime.newFixnum(BERTags.PRINTABLE_STRING));
  95. hash.op_aset(runtime.getCurrentContext(), runtime.newString("serialNumber"),runtime.newFixnum(BERTags.PRINTABLE_STRING));
  96. hash.op_aset(runtime.getCurrentContext(), runtime.newString("dnQualifier"),runtime.newFixnum(BERTags.PRINTABLE_STRING));
  97. hash.op_aset(runtime.getCurrentContext(), runtime.newString("DC"),runtime.newFixnum(BERTags.IA5_STRING));
  98. hash.op_aset(runtime.getCurrentContext(), runtime.newString("domainComponent"),runtime.newFixnum(BERTags.IA5_STRING));
  99. hash.op_aset(runtime.getCurrentContext(), runtime.newString("emailAddress"),runtime.newFixnum(BERTags.IA5_STRING));
  100. cX509Name.setConstant("OBJECT_TYPE_TEMPLATE", hash);
  101. }
  102. public static final int COMPAT = 0;
  103. public static final int RFC2253 = 17892119;
  104. public static final int ONELINE = 8520479;
  105. public static final int MULTILINE = 44302342;
  106. public X509Name(Ruby runtime, RubyClass type) {
  107. super(runtime,type);
  108. oids = new ArrayList<Object>();
  109. values = new ArrayList<Object>();
  110. types = new ArrayList<Object>();
  111. }
  112. private List<Object> oids;
  113. private List<Object> values;
  114. private List<Object> types;
  115. void addEntry(Object oid, Object value, Object type) {
  116. oids.add(oid);
  117. values.add(value);
  118. types.add(type);
  119. }
  120. public static X509Name create(Ruby runtime, org.bouncycastle.asn1.x500.X500Name realName) {
  121. X509Name name = new X509Name(runtime, Utils.getClassFromPath(runtime, "OpenSSL::X509::Name"));
  122. name.fromASN1Sequence((ASN1Sequence)realName.toASN1Primitive());
  123. return name;
  124. }
  125. void fromASN1Sequence(ASN1Sequence seq) {
  126. oids = new ArrayList<Object>();
  127. values = new ArrayList<Object>();
  128. types = new ArrayList<Object>();
  129. if (seq != null) {
  130. for (Enumeration enumRdn = seq.getObjects(); enumRdn.hasMoreElements();) {
  131. ASN1Object element = (ASN1Object) enumRdn.nextElement();
  132. if (element instanceof RDN) {
  133. fromRDNElement(element);
  134. } else if (element instanceof ASN1Sequence) {
  135. fromASN1Sequence(element);
  136. } else {
  137. fromASN1Set(element);
  138. }
  139. }
  140. }
  141. }
  142. private void fromRDNElement(Object element) {
  143. RDN rdn = (RDN)element;
  144. for(AttributeTypeAndValue tv:rdn.getTypesAndValues()) {
  145. oids.add(tv.getType());
  146. if (tv.getValue() instanceof ASN1String) {
  147. values.add(((ASN1String)tv.getValue()).getString());
  148. } else {
  149. values.add(null); //TODO really?
  150. }
  151. types.add(getRuntime().newFixnum(ASN1.idForClass(tv.getValue().getClass())));
  152. }
  153. }
  154. private void fromASN1Set(Object element) {
  155. ASN1Set typeAndValue = ASN1Set.getInstance(element);
  156. for (Enumeration enumRdn = typeAndValue.getObjects(); enumRdn.hasMoreElements();) {
  157. fromASN1Sequence(enumRdn.nextElement());
  158. }
  159. }
  160. private void fromASN1Sequence(Object element) {
  161. ASN1Sequence typeAndValue = ASN1Sequence.getInstance(element);
  162. oids.add(typeAndValue.getObjectAt(0));
  163. if (typeAndValue.getObjectAt(1) instanceof ASN1String) {
  164. values.add(((ASN1String) typeAndValue.getObjectAt(1)).getString());
  165. } else {
  166. values.add(null);
  167. }
  168. types.add(getRuntime().newFixnum(ASN1.idForClass(typeAndValue.getObjectAt(1).getClass())));
  169. }
  170. @JRubyMethod
  171. public IRubyObject initialize(ThreadContext context) {
  172. return this;
  173. }
  174. @JRubyMethod
  175. public IRubyObject initialize(ThreadContext context, IRubyObject str_or_dn) {
  176. return initialize(
  177. context,
  178. str_or_dn,
  179. context.nil);
  180. }
  181. @JRubyMethod
  182. public IRubyObject initialize(ThreadContext context, IRubyObject dn, IRubyObject template) {
  183. Ruby runtime = context.runtime;
  184. if(dn instanceof RubyArray) {
  185. RubyArray ary = (RubyArray)dn;
  186. if(template.isNil()) {
  187. template = runtime.getClassFromPath("OpenSSL::X509::Name").getConstant("OBJECT_TYPE_TEMPLATE");
  188. }
  189. for (int i = 0; i < ary.size(); i++) {
  190. IRubyObject obj = ary.eltOk(i);
  191. if (!(obj instanceof RubyArray)) {
  192. throw runtime.newTypeError(obj, runtime.getArray());
  193. }
  194. RubyArray arr = (RubyArray)obj;
  195. IRubyObject entry0, entry1, entry2;
  196. entry0 = arr.size() > 0 ? arr.eltOk(0) : context.nil;
  197. entry1 = arr.size() > 1 ? arr.eltOk(1) : context.nil;
  198. entry2 = arr.size() > 2 ? arr.eltOk(2) : context.nil;
  199. if (entry2.isNil()) entry2 = template.callMethod(context, "[]", entry0);
  200. if (entry2.isNil()) entry2 = runtime.getClassFromPath("OpenSSL::X509::Name").getConstant("DEFAULT_OBJECT_TYPE");
  201. add_entry(context, entry0, entry1, entry2);
  202. }
  203. } else {
  204. try {
  205. byte[] bytes = OpenSSLImpl.to_der_if_possible(dn).convertToString().getBytes();
  206. ASN1InputStream is = new ASN1InputStream(bytes);
  207. ASN1Sequence seq = (ASN1Sequence)is.readObject();
  208. //StringBuilder b = new StringBuilder();
  209. //printASN(seq, b);
  210. fromASN1Sequence(seq);
  211. } catch(IOException e) { //Do not catch Exception. Want to see nullpointer stacktrace.
  212. throw newX509NameError(runtime, e.getClass().getName() + ":" + e.getLocalizedMessage());
  213. }
  214. }
  215. return this;
  216. }
  217. private void printASN(org.bouncycastle.asn1.ASN1Encodable obj, StringBuilder b) {
  218. printASN(obj,0, b);
  219. }
  220. private void printASN(org.bouncycastle.asn1.ASN1Encodable obj, int indent, StringBuilder b) {
  221. if(obj instanceof org.bouncycastle.asn1.ASN1Sequence) {
  222. for(int i=0;i<indent;i++) {
  223. b.append(" ");
  224. }
  225. b.append("- Sequence:");
  226. for(java.util.Enumeration enm = ((org.bouncycastle.asn1.ASN1Sequence)obj).getObjects();enm.hasMoreElements();) {
  227. printASN((org.bouncycastle.asn1.ASN1Encodable)enm.nextElement(),indent+1, b);
  228. }
  229. } else if(obj instanceof org.bouncycastle.asn1.ASN1Set) {
  230. for(int i=0;i<indent;i++) {
  231. b.append(" ");
  232. }
  233. b.append("- Set:");
  234. for(java.util.Enumeration enm = ((org.bouncycastle.asn1.ASN1Set)obj).getObjects();enm.hasMoreElements();) {
  235. printASN((org.bouncycastle.asn1.ASN1Encodable)enm.nextElement(),indent+1, b);
  236. }
  237. } else {
  238. for(int i=0;i<indent;i++) {
  239. b.append(" ");
  240. }
  241. if(obj instanceof org.bouncycastle.asn1.ASN1String) {
  242. b.append("- ").append(obj).append("=").append(((org.bouncycastle.asn1.ASN1String)obj).getString()).append("[").append(obj.getClass()).append("]");
  243. } else {
  244. b.append("- ").append(obj).append("[").append(obj.getClass()).append("]");
  245. }
  246. }
  247. }
  248. private ASN1ObjectIdentifier getObjectIdentifier(String nameOrOid) {
  249. Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase());
  250. if(null != val1) {
  251. return (ASN1ObjectIdentifier)val1;
  252. }
  253. ASN1ObjectIdentifier val2 = new ASN1ObjectIdentifier(nameOrOid);
  254. return val2;
  255. }
  256. @JRubyMethod
  257. public IRubyObject add_entry(ThreadContext context, IRubyObject oid, IRubyObject value) {
  258. return add_entry(context, oid, value, context.nil);
  259. }
  260. @JRubyMethod
  261. public IRubyObject add_entry(ThreadContext context, IRubyObject _oid, IRubyObject _value, IRubyObject _type) {
  262. Ruby runtime = context.runtime;
  263. String oid = _oid.convertToString().toString();
  264. String value = _value.convertToString().toString();
  265. IRubyObject type = !_type.isNil() ? _type : runtime.getClassFromPath("OpenSSL::X509::Name").getConstant("OBJECT_TYPE_TEMPLATE").callMethod(context, "[]", _oid);
  266. ASN1ObjectIdentifier oid_v;
  267. try {
  268. oid_v = getObjectIdentifier(oid);
  269. } catch (IllegalArgumentException e) {
  270. throw newX509NameError(getRuntime(), "invalid field name: " + e.getMessage());
  271. }
  272. if (null == oid_v) {
  273. throw newX509NameError(getRuntime(), null);
  274. }
  275. oids.add(oid_v);
  276. values.add(value);
  277. types.add(type);
  278. return this;
  279. }
  280. @JRubyMethod(name="to_s", rest=true)
  281. public IRubyObject _to_s(IRubyObject[] args) {
  282. /*
  283. Should follow parameters like this:
  284. if 0 (COMPAT):
  285. irb(main):025:0> x.to_s(OpenSSL::X509::Name::COMPAT)
  286. => "CN=ola.bini, O=sweden/streetAddress=sweden, O=sweden/2.5.4.43343=sweden"
  287. irb(main):026:0> x.to_s(OpenSSL::X509::Name::ONELINE)
  288. => "CN = ola.bini, O = sweden, streetAddress = sweden, O = sweden, 2.5.4.43343 = sweden"
  289. irb(main):027:0> x.to_s(OpenSSL::X509::Name::MULTILINE)
  290. => "commonName = ola.bini\norganizationName = sweden\nstreetAddress = sweden\norganizationName = sweden\n2.5.4.43343 = sweden"
  291. irb(main):028:0> x.to_s(OpenSSL::X509::Name::RFC2253)
  292. => "2.5.4.43343=#0C0673776564656E,O=sweden,streetAddress=sweden,O=sweden,CN=ola.bini"
  293. else
  294. => /CN=ola.bini/O=sweden/streetAddress=sweden/O=sweden/2.5.4.43343=sweden
  295. */
  296. int flag = -1;
  297. if(args.length > 0 && !args[0].isNil()) {
  298. flag = RubyNumeric.fix2int(args[0]);
  299. }
  300. StringBuilder sb = new StringBuilder();
  301. Map<ASN1ObjectIdentifier, String> lookup = ASN1.getSymLookup(getRuntime());
  302. Iterator<Object> oiter = null;
  303. Iterator<Object> viter = null;
  304. if(flag == RFC2253) {
  305. List<Object> ao = new ArrayList<Object>(oids);
  306. List<Object> av = new ArrayList<Object>(values);
  307. java.util.Collections.reverse(ao);
  308. java.util.Collections.reverse(av);
  309. oiter = ao.iterator();
  310. viter = av.iterator();
  311. } else {
  312. oiter = oids.iterator();
  313. viter = values.iterator();
  314. }
  315. String sep = "";
  316. for(;oiter.hasNext();) {
  317. ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)oiter.next();
  318. String val = (String)viter.next();
  319. String outOid = lookup.get(oid);
  320. if(null == outOid) {
  321. outOid = oid.toString();
  322. }
  323. if(flag == RFC2253) {
  324. sb.append(sep).append(outOid).append("=").append(val);
  325. sep = ",";
  326. } else {
  327. sb.append("/").append(outOid).append("=").append(val);
  328. }
  329. }
  330. return getRuntime().newString(sb.toString());
  331. }
  332. @Override
  333. @JRubyMethod
  334. public RubyArray to_a() {
  335. List<IRubyObject> entries = new ArrayList<IRubyObject>();
  336. Map<ASN1ObjectIdentifier, String> lookup = ASN1.getSymLookup(getRuntime());
  337. Iterator<Object> oiter = oids.iterator();
  338. Iterator<Object> viter = values.iterator();
  339. Iterator<Object> titer = types.iterator();
  340. for(;oiter.hasNext();) {
  341. ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)oiter.next();
  342. String val = (String)viter.next();
  343. String outOid = lookup.get(oid);
  344. if(null == outOid) {
  345. outOid = "UNDEF";
  346. }
  347. IRubyObject type = (IRubyObject)titer.next();
  348. entries.add(getRuntime().newArrayNoCopy(new IRubyObject[]{getRuntime().newString(outOid),getRuntime().newString(val),type}));
  349. }
  350. return getRuntime().newArray(entries);
  351. }
  352. @JRubyMethod(name={"cmp","<=>"})
  353. public IRubyObject cmp(IRubyObject other) {
  354. if(eql_p(other).isTrue()) {
  355. return RubyFixnum.zero(getRuntime());
  356. }
  357. // TODO: huh?
  358. return RubyFixnum.one(getRuntime());
  359. }
  360. org.bouncycastle.asn1.x509.X509Name getRealName() {
  361. return new org.bouncycastle.asn1.x509.X509Name(new Vector<Object>(oids),new Vector<Object>(values));
  362. }
  363. X500Name getX500Name() {
  364. return X500Name.getInstance(getRealName().toASN1Primitive());
  365. }
  366. @Override
  367. @JRubyMethod(name="eql?")
  368. public IRubyObject eql_p(IRubyObject other) {
  369. if(!(other instanceof X509Name)) {
  370. return getRuntime().getFalse();
  371. }
  372. X509Name o = (X509Name)other;
  373. org.bouncycastle.asn1.x509.X509Name nm = new org.bouncycastle.asn1.x509.X509Name(new Vector<Object>(oids),new Vector<Object>(values));
  374. org.bouncycastle.asn1.x509.X509Name o_nm = new org.bouncycastle.asn1.x509.X509Name(new Vector<Object>(o.oids),new Vector<Object>(o.values));
  375. return nm.equals(o_nm) ? getRuntime().getTrue() : getRuntime().getFalse();
  376. }
  377. @Override
  378. @JRubyMethod
  379. public RubyFixnum hash() {
  380. Name name = new Name( getX500Name() );
  381. return getRuntime().newFixnum(name.hash());
  382. }
  383. @JRubyMethod
  384. public IRubyObject to_der() {
  385. DLSequence seq = null;
  386. if(oids.size()>0) {
  387. ASN1EncodableVector vec = new ASN1EncodableVector();
  388. ASN1EncodableVector sVec = new ASN1EncodableVector();
  389. ASN1ObjectIdentifier lstOid = null;
  390. for (int i = 0; i != oids.size(); i++) {
  391. ASN1EncodableVector v = new ASN1EncodableVector();
  392. ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)oids.get(i);
  393. v.add(oid);
  394. String str = (String)values.get(i);
  395. v.add(convert(oid,str,RubyNumeric.fix2int(((RubyFixnum)types.get(i)))));
  396. if (lstOid == null) {
  397. sVec.add(new DLSequence(v));
  398. } else {
  399. vec.add(new DLSet(sVec));
  400. sVec = new ASN1EncodableVector();
  401. sVec.add(new DLSequence(v));
  402. }
  403. lstOid = oid;
  404. }
  405. vec.add(new DLSet(sVec));
  406. seq = new DLSequence(vec);
  407. } else {
  408. seq = new DLSequence();
  409. }
  410. try {
  411. return RubyString.newString(getRuntime(), seq.getEncoded(ASN1Encoding.DER));
  412. } catch (IOException ex) {
  413. throw newX509NameError(getRuntime(), ex.getMessage());
  414. }
  415. }
  416. private ASN1Primitive convert(ASN1ObjectIdentifier oid, String value, int type) {
  417. try {
  418. Class<? extends ASN1Encodable> clzz = ASN1.classForId(type);
  419. if (clzz != null) {
  420. java.lang.reflect.Constructor<?> ctor = clzz.getConstructor(new Class[]{String.class});
  421. if (null != ctor) {
  422. return (ASN1Primitive) ctor.newInstance(new Object[]{value});
  423. }
  424. }
  425. return new X509DefaultEntryConverter().getConvertedValue(oid, value);
  426. } catch (Exception e) {
  427. throw newX509NameError(getRuntime(), e.getMessage());
  428. }
  429. }
  430. private static RaiseException newX509NameError(Ruby runtime, String message) {
  431. return Utils.newError(runtime, "OpenSSL::X509::NameError", message);
  432. }
  433. }// X509Name