SslCertificate.java revision a5987a510187749c32f0f68f8fc54e1334f91be6
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net.http; 18 19import android.os.Bundle; 20 21import java.text.ParseException; 22import java.text.SimpleDateFormat; 23import java.util.Date; 24import java.util.Vector; 25 26import java.security.cert.X509Certificate; 27 28import org.bouncycastle.asn1.DERObjectIdentifier; 29import org.bouncycastle.asn1.x509.X509Name; 30 31/** 32 * SSL certificate info (certificate details) class 33 */ 34public class SslCertificate { 35 36 /** 37 * SimpleDateFormat pattern for an ISO 8601 date 38 */ 39 private static String ISO_8601_DATE_FORMAT = "yyyy-MM-dd HH:mm:ssZ"; 40 41 /** 42 * Name of the entity this certificate is issued to 43 */ 44 private DName mIssuedTo; 45 46 /** 47 * Name of the entity this certificate is issued by 48 */ 49 private DName mIssuedBy; 50 51 /** 52 * Not-before date from the validity period 53 */ 54 private Date mValidNotBefore; 55 56 /** 57 * Not-after date from the validity period 58 */ 59 private Date mValidNotAfter; 60 61 /** 62 * Bundle key names 63 */ 64 private static final String ISSUED_TO = "issued-to"; 65 private static final String ISSUED_BY = "issued-by"; 66 private static final String VALID_NOT_BEFORE = "valid-not-before"; 67 private static final String VALID_NOT_AFTER = "valid-not-after"; 68 69 /** 70 * Saves the certificate state to a bundle 71 * @param certificate The SSL certificate to store 72 * @return A bundle with the certificate stored in it or null if fails 73 */ 74 public static Bundle saveState(SslCertificate certificate) { 75 Bundle bundle = null; 76 77 if (certificate != null) { 78 bundle = new Bundle(); 79 80 bundle.putString(ISSUED_TO, certificate.getIssuedTo().getDName()); 81 bundle.putString(ISSUED_BY, certificate.getIssuedBy().getDName()); 82 83 bundle.putString(VALID_NOT_BEFORE, certificate.getValidNotBefore()); 84 bundle.putString(VALID_NOT_AFTER, certificate.getValidNotAfter()); 85 } 86 87 return bundle; 88 } 89 90 /** 91 * Restores the certificate stored in the bundle 92 * @param bundle The bundle with the certificate state stored in it 93 * @return The SSL certificate stored in the bundle or null if fails 94 */ 95 public static SslCertificate restoreState(Bundle bundle) { 96 if (bundle != null) { 97 return new SslCertificate( 98 bundle.getString(ISSUED_TO), 99 bundle.getString(ISSUED_BY), 100 bundle.getString(VALID_NOT_BEFORE), 101 bundle.getString(VALID_NOT_AFTER)); 102 } 103 104 return null; 105 } 106 107 /** 108 * Creates a new SSL certificate object 109 * @param issuedTo The entity this certificate is issued to 110 * @param issuedBy The entity that issued this certificate 111 * @param validNotBefore The not-before date from the certificate validity period in ISO 8601 format 112 * @param validNotAfter The not-after date from the certificate validity period in ISO 8601 format 113 * @deprecated Use {@link #SslCertificate(String, String, Date, Date)} 114 */ 115 public SslCertificate( 116 String issuedTo, String issuedBy, String validNotBefore, String validNotAfter) { 117 this(issuedTo, issuedBy, parseDate(validNotBefore), parseDate(validNotAfter)); 118 } 119 120 /** 121 * Creates a new SSL certificate object 122 * @param issuedTo The entity this certificate is issued to 123 * @param issuedBy The entity that issued this certificate 124 * @param validNotBefore The not-before date from the certificate validity period 125 * @param validNotAfter The not-after date from the certificate validity period 126 */ 127 public SslCertificate( 128 String issuedTo, String issuedBy, Date validNotBefore, Date validNotAfter) { 129 mIssuedTo = new DName(issuedTo); 130 mIssuedBy = new DName(issuedBy); 131 mValidNotBefore = cloneDate(validNotBefore); 132 mValidNotAfter = cloneDate(validNotAfter); 133 } 134 135 /** 136 * Creates a new SSL certificate object from an X509 certificate 137 * @param certificate X509 certificate 138 */ 139 public SslCertificate(X509Certificate certificate) { 140 this(certificate.getSubjectDN().getName(), 141 certificate.getIssuerDN().getName(), 142 certificate.getNotBefore(), 143 certificate.getNotAfter()); 144 } 145 146 /** 147 * @return Not-before date from the certificate validity period or 148 * "" if none has been set 149 */ 150 public Date getValidNotBeforeDate() { 151 return cloneDate(mValidNotBefore); 152 } 153 154 /** 155 * @return Not-before date from the certificate validity period in 156 * ISO 8601 format or "" if none has been set 157 * 158 * @deprecated Use {@link #getValidNotBeforeDate()} 159 */ 160 public String getValidNotBefore() { 161 return formatDate(mValidNotBefore); 162 } 163 164 /** 165 * @return Not-after date from the certificate validity period or 166 * "" if none has been set 167 */ 168 public Date getValidNotAfterDate() { 169 return cloneDate(mValidNotAfter); 170 } 171 172 /** 173 * @return Not-after date from the certificate validity period in 174 * ISO 8601 format or "" if none has been set 175 * 176 * @deprecated Use {@link #getValidNotAfterDate()} 177 */ 178 public String getValidNotAfter() { 179 return formatDate(mValidNotAfter); 180 } 181 182 /** 183 * @return Issued-to distinguished name or null if none has been set 184 */ 185 public DName getIssuedTo() { 186 return mIssuedTo; 187 } 188 189 /** 190 * @return Issued-by distinguished name or null if none has been set 191 */ 192 public DName getIssuedBy() { 193 return mIssuedBy; 194 } 195 196 /** 197 * @return A string representation of this certificate for debugging 198 */ 199 public String toString() { 200 return 201 "Issued to: " + mIssuedTo.getDName() + ";\n" + 202 "Issued by: " + mIssuedBy.getDName() + ";\n"; 203 } 204 205 /** 206 * Parse an ISO 8601 date converting ParseExceptions to a null result; 207 */ 208 private static Date parseDate(String string) { 209 try { 210 return new SimpleDateFormat(ISO_8601_DATE_FORMAT).parse(string); 211 } catch (ParseException e) { 212 return null; 213 } 214 } 215 216 /** 217 * Format a date as an ISO 8601 string, return "" for a null date 218 */ 219 private static String formatDate(Date date) { 220 if (date == null) { 221 return ""; 222 } 223 return new SimpleDateFormat(ISO_8601_DATE_FORMAT).format(date); 224 } 225 226 /** 227 * Clone a possibly null Date 228 */ 229 private static Date cloneDate(Date date) { 230 if (date == null) { 231 return null; 232 } 233 return (Date) date.clone(); 234 } 235 236 /** 237 * A distinguished name helper class: a 3-tuple of: 238 * - common name (CN), 239 * - organization (O), 240 * - organizational unit (OU) 241 */ 242 public class DName { 243 /** 244 * Distinguished name (normally includes CN, O, and OU names) 245 */ 246 private String mDName; 247 248 /** 249 * Common-name (CN) component of the name 250 */ 251 private String mCName; 252 253 /** 254 * Organization (O) component of the name 255 */ 256 private String mOName; 257 258 /** 259 * Organizational Unit (OU) component of the name 260 */ 261 private String mUName; 262 263 /** 264 * Creates a new distinguished name 265 * @param dName The distinguished name 266 */ 267 public DName(String dName) { 268 if (dName != null) { 269 mDName = dName; 270 try { 271 X509Name x509Name = new X509Name(dName); 272 273 Vector val = x509Name.getValues(); 274 Vector oid = x509Name.getOIDs(); 275 276 for (int i = 0; i < oid.size(); i++) { 277 if (oid.elementAt(i).equals(X509Name.CN)) { 278 mCName = (String) val.elementAt(i); 279 continue; 280 } 281 282 if (oid.elementAt(i).equals(X509Name.O)) { 283 mOName = (String) val.elementAt(i); 284 continue; 285 } 286 287 if (oid.elementAt(i).equals(X509Name.OU)) { 288 mUName = (String) val.elementAt(i); 289 continue; 290 } 291 } 292 } catch (IllegalArgumentException ex) { 293 // thrown if there is an error parsing the string 294 } 295 } 296 } 297 298 /** 299 * @return The distinguished name (normally includes CN, O, and OU names) 300 */ 301 public String getDName() { 302 return mDName != null ? mDName : ""; 303 } 304 305 /** 306 * @return The Common-name (CN) component of this name 307 */ 308 public String getCName() { 309 return mCName != null ? mCName : ""; 310 } 311 312 /** 313 * @return The Organization (O) component of this name 314 */ 315 public String getOName() { 316 return mOName != null ? mOName : ""; 317 } 318 319 /** 320 * @return The Organizational Unit (OU) component of this name 321 */ 322 public String getUName() { 323 return mUName != null ? mUName : ""; 324 } 325 } 326} 327