summaryrefslogtreecommitdiffstats
path: root/base/util
diff options
context:
space:
mode:
authorEndi Sukma Dewata <edewata@redhat.com>2012-03-24 02:27:47 -0500
committerEndi Sukma Dewata <edewata@redhat.com>2012-03-26 11:43:54 -0500
commit621d9e5c413e561293d7484b93882d985b3fe15f (patch)
tree638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/util
parent40d3643b8d91886bf210aa27f711731c81a11e49 (diff)
downloadpki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz
pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz
pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131
Diffstat (limited to 'base/util')
-rw-r--r--base/util/CMakeLists.txt4
-rw-r--r--base/util/LICENSE291
-rw-r--r--base/util/src/CMakeLists.txt369
-rw-r--r--base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java1292
-rw-r--r--base/util/src/com/netscape/cmsutil/crypto/Module.java75
-rw-r--r--base/util/src/com/netscape/cmsutil/crypto/Token.java57
-rw-r--r--base/util/src/com/netscape/cmsutil/http/ConnectAsync.java46
-rw-r--r--base/util/src/com/netscape/cmsutil/http/Http.java31
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpClient.java217
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpEofException.java35
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpMessage.java163
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java35
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpRequest.java137
-rw-r--r--base/util/src/com/netscape/cmsutil/http/HttpResponse.java139
-rw-r--r--base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java182
-rw-r--r--base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java101
-rw-r--r--base/util/src/com/netscape/cmsutil/net/ISocketFactory.java38
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/BasicOCSPResponse.java195
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/CertID.java155
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/CertStatus.java35
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/GoodInfo.java98
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/KeyHashID.java105
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/NameID.java106
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/OCSPRequest.java140
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/OCSPResponse.java135
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/OCSPResponseStatus.java120
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/Request.java147
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/ResponderID.java34
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/Response.java34
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/ResponseBytes.java130
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/ResponseData.java222
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/RevokedInfo.java113
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/Signature.java159
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/SingleResponse.java182
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/TBSRequest.java210
-rw-r--r--base/util/src/com/netscape/cmsutil/ocsp/UnknownInfo.java95
-rw-r--r--base/util/src/com/netscape/cmsutil/password/IPasswordReader.java29
-rw-r--r--base/util/src/com/netscape/cmsutil/password/IPasswordStore.java34
-rw-r--r--base/util/src/com/netscape/cmsutil/password/IPasswordWriter.java30
-rw-r--r--base/util/src/com/netscape/cmsutil/password/PlainPasswordFile.java70
-rw-r--r--base/util/src/com/netscape/cmsutil/password/PlainPasswordReader.java58
-rw-r--r--base/util/src/com/netscape/cmsutil/password/PlainPasswordWriter.java56
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AccessAccept.java27
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AccessChallenge.java27
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AccessReject.java27
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AccessRequest.java25
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/Attribute.java97
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AttributeFactory.java154
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/AttributeSet.java56
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/Authenticator.java24
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CHAPChallengeAttribute.java38
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CHAPPasswordAttribute.java55
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CallbackIdAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CallbackNumberAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CallerStationIdAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/CallingStationIdAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ChallengeException.java43
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FilterIdAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkLinkAttribute.java51
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkNetworkAttribute.java49
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkZoneAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedCompressionAttribute.java54
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedIPAddressAttribute.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedIPNetmaskAttribute.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedIPXNetworkAttribute.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedMTUAttribute.java49
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedProtocolAttribute.java56
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedRouteAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/FramedRoutingAttribute.java54
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/GenericAttribute.java35
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/IdleTimeoutAttribute.java52
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginIPHostAttribute.java52
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginLATGroupAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginLATNodeAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginLATPortAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginLATServiceAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginServiceAttribute.java58
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/LoginTCPPortAttribute.java52
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASClassAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASIPAddressAttribute.java41
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASIdentifierAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASPacket.java52
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASPortAttribute.java48
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/NASPortTypeAttribute.java53
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/Packet.java70
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/PacketFactory.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/PortLimitAttribute.java51
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ProxyStateAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/RadiusConn.java230
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/RejectException.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ReplyMessageAttribute.java40
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/RequestAuthenticator.java44
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ResponseAuthenticator.java32
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ServerPacket.java47
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/ServiceTypeAttribute.java61
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/SessionTimeoutAttribute.java48
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/StateAttribute.java45
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/TerminationActionAttribute.java55
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/UserNameAttribute.java39
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/UserPasswordAttribute.java73
-rw-r--r--base/util/src/com/netscape/cmsutil/radius/VendorSpecificAttribute.java52
-rw-r--r--base/util/src/com/netscape/cmsutil/scep/CRSPKIMessage.java905
-rw-r--r--base/util/src/com/netscape/cmsutil/util/Cert.java186
-rw-r--r--base/util/src/com/netscape/cmsutil/util/Fmt.java605
-rw-r--r--base/util/src/com/netscape/cmsutil/util/HMACDigest.java198
-rw-r--r--base/util/src/com/netscape/cmsutil/util/Utils.java276
-rw-r--r--base/util/src/com/netscape/cmsutil/xml/XMLObject.java187
-rw-r--r--base/util/src/netscape/net/NetworkClient.java87
-rw-r--r--base/util/src/netscape/net/TransferProtocolClient.java127
-rw-r--r--base/util/src/netscape/net/smtp/SmtpClient.java235
-rw-r--r--base/util/src/netscape/net/smtp/SmtpProtocolException.java35
-rw-r--r--base/util/src/netscape/security/acl/AclEntryImpl.java182
-rw-r--r--base/util/src/netscape/security/acl/AclImpl.java391
-rw-r--r--base/util/src/netscape/security/acl/AllPermissionsImpl.java43
-rw-r--r--base/util/src/netscape/security/acl/GroupImpl.java173
-rw-r--r--base/util/src/netscape/security/acl/OwnerImpl.java105
-rw-r--r--base/util/src/netscape/security/acl/PermissionImpl.java65
-rw-r--r--base/util/src/netscape/security/acl/PrincipalImpl.java77
-rw-r--r--base/util/src/netscape/security/acl/WorldGroupImpl.java42
-rw-r--r--base/util/src/netscape/security/extensions/AccessDescription.java76
-rw-r--r--base/util/src/netscape/security/extensions/AuthInfoAccessExtension.java272
-rw-r--r--base/util/src/netscape/security/extensions/CertInfo.java120
-rw-r--r--base/util/src/netscape/security/extensions/CertificateRenewalWindowExtension.java190
-rw-r--r--base/util/src/netscape/security/extensions/CertificateScopeEntry.java103
-rw-r--r--base/util/src/netscape/security/extensions/CertificateScopeOfUseExtension.java199
-rw-r--r--base/util/src/netscape/security/extensions/ExtendedKeyUsageExtension.java226
-rw-r--r--base/util/src/netscape/security/extensions/GenericASN1Extension.java448
-rw-r--r--base/util/src/netscape/security/extensions/InhibitAnyPolicyExtension.java179
-rw-r--r--base/util/src/netscape/security/extensions/KerberosName.java135
-rw-r--r--base/util/src/netscape/security/extensions/NSCertTypeExtension.java377
-rw-r--r--base/util/src/netscape/security/extensions/OCSPNoCheckExtension.java153
-rw-r--r--base/util/src/netscape/security/extensions/PresenceServerExtension.java321
-rw-r--r--base/util/src/netscape/security/extensions/SubjectInfoAccessExtension.java254
-rw-r--r--base/util/src/netscape/security/pkcs/ContentInfo.java155
-rw-r--r--base/util/src/netscape/security/pkcs/EncodingException.java33
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS10.java343
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS10Attribute.java238
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS10Attributes.java147
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS7.java446
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS8Key.java435
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS9Attribute.java1123
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS9Attributes.java312
-rw-r--r--base/util/src/netscape/security/pkcs/ParsingException.java35
-rw-r--r--base/util/src/netscape/security/pkcs/SignerInfo.java347
-rw-r--r--base/util/src/netscape/security/provider/CMS.java52
-rw-r--r--base/util/src/netscape/security/provider/DSA.java660
-rwxr-xr-xbase/util/src/netscape/security/provider/DSAKeyFactory.java232
-rw-r--r--base/util/src/netscape/security/provider/DSAKeyPairGenerator.java398
-rwxr-xr-xbase/util/src/netscape/security/provider/DSAParameterGenerator.java299
-rwxr-xr-xbase/util/src/netscape/security/provider/DSAParameters.java130
-rw-r--r--base/util/src/netscape/security/provider/DSAPrivateKey.java147
-rw-r--r--base/util/src/netscape/security/provider/DSAPublicKey.java133
-rw-r--r--base/util/src/netscape/security/provider/MD5.java378
-rw-r--r--base/util/src/netscape/security/provider/RSAPublicKey.java152
-rw-r--r--base/util/src/netscape/security/provider/SHA.java349
-rw-r--r--base/util/src/netscape/security/provider/Sun.java135
-rw-r--r--base/util/src/netscape/security/provider/X509CertificateFactory.java61
-rw-r--r--base/util/src/netscape/security/util/ASN1CharStrConvMap.java168
-rw-r--r--base/util/src/netscape/security/util/ASN1CharsetProvider.java30
-rw-r--r--base/util/src/netscape/security/util/BigInt.java210
-rw-r--r--base/util/src/netscape/security/util/BitArray.java257
-rw-r--r--base/util/src/netscape/security/util/ByteArrayLexOrder.java58
-rw-r--r--base/util/src/netscape/security/util/ByteArrayTagOrder.java44
-rw-r--r--base/util/src/netscape/security/util/CertPrettyPrint.java345
-rw-r--r--base/util/src/netscape/security/util/CrlPrettyPrint.java271
-rw-r--r--base/util/src/netscape/security/util/DerEncoder.java40
-rw-r--r--base/util/src/netscape/security/util/DerInputBuffer.java186
-rw-r--r--base/util/src/netscape/security/util/DerInputStream.java662
-rw-r--r--base/util/src/netscape/security/util/DerOutputStream.java729
-rw-r--r--base/util/src/netscape/security/util/DerValue.java715
-rw-r--r--base/util/src/netscape/security/util/ExtPrettyPrint.java1653
-rw-r--r--base/util/src/netscape/security/util/IA5Charset.java24
-rw-r--r--base/util/src/netscape/security/util/IA5CharsetDecoder.java62
-rw-r--r--base/util/src/netscape/security/util/IA5CharsetEncoder.java69
-rw-r--r--base/util/src/netscape/security/util/ObjectIdentifier.java426
-rw-r--r--base/util/src/netscape/security/util/PrettyPrintFormat.java160
-rw-r--r--base/util/src/netscape/security/util/PrettyPrintResources.java301
-rw-r--r--base/util/src/netscape/security/util/PrintableCharset.java46
-rw-r--r--base/util/src/netscape/security/util/PrintableCharsetDecoder.java69
-rw-r--r--base/util/src/netscape/security/util/PrintableCharsetEncoder.java71
-rw-r--r--base/util/src/netscape/security/util/PubKeyPrettyPrint.java121
-rw-r--r--base/util/src/netscape/security/util/UniversalCharset.java24
-rw-r--r--base/util/src/netscape/security/util/UniversalCharsetDecoder.java98
-rw-r--r--base/util/src/netscape/security/util/UniversalCharsetEncoder.java68
-rwxr-xr-xbase/util/src/netscape/security/x509/ACertAttrSet.java141
-rw-r--r--base/util/src/netscape/security/x509/AVA.java301
-rw-r--r--base/util/src/netscape/security/x509/AVAValueConverter.java86
-rw-r--r--base/util/src/netscape/security/x509/AlgIdDSA.java185
-rw-r--r--base/util/src/netscape/security/x509/AlgorithmId.java767
-rw-r--r--base/util/src/netscape/security/x509/Attribute.java325
-rw-r--r--base/util/src/netscape/security/x509/AuthorityKeyIdentifierExtension.java340
-rw-r--r--base/util/src/netscape/security/x509/BasicConstraintsExtension.java295
-rw-r--r--base/util/src/netscape/security/x509/CPSuri.java66
-rw-r--r--base/util/src/netscape/security/x509/CRLDistributionPoint.java467
-rw-r--r--base/util/src/netscape/security/x509/CRLDistributionPointsExtension.java391
-rwxr-xr-xbase/util/src/netscape/security/x509/CRLExtensions.java229
-rwxr-xr-xbase/util/src/netscape/security/x509/CRLNumberExtension.java226
-rw-r--r--base/util/src/netscape/security/x509/CRLReasonExtension.java234
-rw-r--r--base/util/src/netscape/security/x509/CertAndKeyGen.java290
-rwxr-xr-xbase/util/src/netscape/security/x509/CertAttrSet.java120
-rw-r--r--base/util/src/netscape/security/x509/CertException.java165
-rw-r--r--base/util/src/netscape/security/x509/CertParseError.java40
-rw-r--r--base/util/src/netscape/security/x509/CertificateAlgorithmId.java189
-rw-r--r--base/util/src/netscape/security/x509/CertificateChain.java137
-rw-r--r--base/util/src/netscape/security/x509/CertificateExtensions.java276
-rw-r--r--base/util/src/netscape/security/x509/CertificateIssuerExtension.java242
-rw-r--r--base/util/src/netscape/security/x509/CertificateIssuerName.java172
-rw-r--r--base/util/src/netscape/security/x509/CertificateIssuerUniqueIdentity.java185
-rw-r--r--base/util/src/netscape/security/x509/CertificatePoliciesExtension.java338
-rw-r--r--base/util/src/netscape/security/x509/CertificatePolicyId.java85
-rw-r--r--base/util/src/netscape/security/x509/CertificatePolicyInfo.java110
-rw-r--r--base/util/src/netscape/security/x509/CertificatePolicyMap.java100
-rw-r--r--base/util/src/netscape/security/x509/CertificatePolicySet.java86
-rw-r--r--base/util/src/netscape/security/x509/CertificateSerialNumber.java191
-rw-r--r--base/util/src/netscape/security/x509/CertificateSubjectName.java203
-rw-r--r--base/util/src/netscape/security/x509/CertificateSubjectUniqueIdentity.java185
-rw-r--r--base/util/src/netscape/security/x509/CertificateValidity.java306
-rw-r--r--base/util/src/netscape/security/x509/CertificateVersion.java247
-rw-r--r--base/util/src/netscape/security/x509/CertificateX509Key.java190
-rw-r--r--base/util/src/netscape/security/x509/DNSName.java82
-rwxr-xr-xbase/util/src/netscape/security/x509/DeltaCRLIndicatorExtension.java239
-rw-r--r--base/util/src/netscape/security/x509/DirStrConverter.java171
-rw-r--r--base/util/src/netscape/security/x509/DisplayText.java82
-rw-r--r--base/util/src/netscape/security/x509/EDIPartyName.java154
-rw-r--r--base/util/src/netscape/security/x509/Extension.java199
-rw-r--r--base/util/src/netscape/security/x509/Extensions.java226
-rw-r--r--base/util/src/netscape/security/x509/FreshestCRLExtension.java396
-rw-r--r--base/util/src/netscape/security/x509/GeneralName.java199
-rw-r--r--base/util/src/netscape/security/x509/GeneralNameInterface.java60
-rw-r--r--base/util/src/netscape/security/x509/GeneralNames.java150
-rw-r--r--base/util/src/netscape/security/x509/GeneralNamesException.java50
-rw-r--r--base/util/src/netscape/security/x509/GeneralSubtree.java159
-rw-r--r--base/util/src/netscape/security/x509/GeneralSubtrees.java106
-rw-r--r--base/util/src/netscape/security/x509/GenericValueConverter.java143
-rw-r--r--base/util/src/netscape/security/x509/HoldInstructionExtension.java354
-rw-r--r--base/util/src/netscape/security/x509/IA5StringConverter.java123
-rw-r--r--base/util/src/netscape/security/x509/IPAddressName.java277
-rw-r--r--base/util/src/netscape/security/x509/InvalidIPAddressException.java33
-rwxr-xr-xbase/util/src/netscape/security/x509/InvalidityDateExtension.java241
-rw-r--r--base/util/src/netscape/security/x509/IssuerAlternativeNameExtension.java240
-rw-r--r--base/util/src/netscape/security/x509/IssuingDistributionPoint.java315
-rw-r--r--base/util/src/netscape/security/x509/IssuingDistributionPointExtension.java416
-rw-r--r--base/util/src/netscape/security/x509/KeyIdentifier.java87
-rw-r--r--base/util/src/netscape/security/x509/KeyUsageExtension.java414
-rw-r--r--base/util/src/netscape/security/x509/LdapDNStrConverter.java144
-rw-r--r--base/util/src/netscape/security/x509/LdapV3DNStrConverter.java824
-rw-r--r--base/util/src/netscape/security/x509/NSCCommentExtension.java230
-rw-r--r--base/util/src/netscape/security/x509/NameConstraintsExtension.java315
-rw-r--r--base/util/src/netscape/security/x509/NoticeReference.java94
-rw-r--r--base/util/src/netscape/security/x509/OIDMap.java303
-rw-r--r--base/util/src/netscape/security/x509/OIDName.java90
-rw-r--r--base/util/src/netscape/security/x509/OtherName.java208
-rw-r--r--base/util/src/netscape/security/x509/PKIXExtensions.java185
-rw-r--r--base/util/src/netscape/security/x509/PolicyConstraint.java136
-rw-r--r--base/util/src/netscape/security/x509/PolicyConstraintsExtension.java306
-rw-r--r--base/util/src/netscape/security/x509/PolicyMappingsExtension.java258
-rw-r--r--base/util/src/netscape/security/x509/PolicyQualifierInfo.java118
-rw-r--r--base/util/src/netscape/security/x509/PolicyQualifiers.java107
-rw-r--r--base/util/src/netscape/security/x509/PrintableConverter.java114
-rw-r--r--base/util/src/netscape/security/x509/PrivateKeyUsageExtension.java339
-rw-r--r--base/util/src/netscape/security/x509/Qualifier.java63
-rw-r--r--base/util/src/netscape/security/x509/RDN.java303
-rw-r--r--base/util/src/netscape/security/x509/RFC1779StrConverter.java102
-rw-r--r--base/util/src/netscape/security/x509/RFC822Name.java85
-rwxr-xr-xbase/util/src/netscape/security/x509/ReasonFlags.java283
-rw-r--r--base/util/src/netscape/security/x509/RevocationReason.java119
-rwxr-xr-xbase/util/src/netscape/security/x509/RevokedCertImpl.java454
-rw-r--r--base/util/src/netscape/security/x509/RevokedCertificate.java95
-rw-r--r--base/util/src/netscape/security/x509/SerialNumber.java124
-rw-r--r--base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java242
-rw-r--r--base/util/src/netscape/security/x509/SubjectDirAttributesExtension.java286
-rw-r--r--base/util/src/netscape/security/x509/SubjectKeyIdentifierExtension.java222
-rw-r--r--base/util/src/netscape/security/x509/URIName.java85
-rw-r--r--base/util/src/netscape/security/x509/UniqueIdentity.java112
-rw-r--r--base/util/src/netscape/security/x509/UserNotice.java96
-rw-r--r--base/util/src/netscape/security/x509/X500Name.java699
-rw-r--r--base/util/src/netscape/security/x509/X500NameAttrMap.java376
-rw-r--r--base/util/src/netscape/security/x509/X500Signer.java116
-rw-r--r--base/util/src/netscape/security/x509/X509AttributeName.java64
-rwxr-xr-xbase/util/src/netscape/security/x509/X509CRLImpl.java1071
-rw-r--r--base/util/src/netscape/security/x509/X509Cert.java849
-rwxr-xr-xbase/util/src/netscape/security/x509/X509CertImpl.java1226
-rw-r--r--base/util/src/netscape/security/x509/X509CertInfo.java964
-rw-r--r--base/util/src/netscape/security/x509/X509ExtensionException.java54
-rw-r--r--base/util/src/netscape/security/x509/X509Key.java508
-rw-r--r--base/util/test/CMakeLists.txt60
-rw-r--r--base/util/test/com/netscape/security/extensions/GenericASN1ExtensionTest.java72
-rw-r--r--base/util/test/com/netscape/security/util/BMPStringTest.java274
-rw-r--r--base/util/test/com/netscape/security/util/IA5StringTest.java273
-rw-r--r--base/util/test/com/netscape/security/util/JSSUtil.java73
-rw-r--r--base/util/test/com/netscape/security/util/PrintableStringTest.java290
-rw-r--r--base/util/test/com/netscape/security/util/StringTestUtil.java79
-rw-r--r--base/util/test/com/netscape/security/util/TeletexStringTest.java273
-rw-r--r--base/util/test/com/netscape/security/util/UTF8StringTest.java262
-rw-r--r--base/util/test/com/netscape/security/util/UniversalStringTest.java262
-rw-r--r--base/util/test/com/netscape/security/x509/ConverterTestUtil.java22
-rw-r--r--base/util/test/com/netscape/security/x509/DirStrConverterTest.java122
-rw-r--r--base/util/test/com/netscape/security/x509/GenericValueConverterTest.java125
-rw-r--r--base/util/test/com/netscape/security/x509/IA5StringConverterTest.java93
-rw-r--r--base/util/test/com/netscape/security/x509/PrintableConverterTest.java103
300 files changed, 57072 insertions, 0 deletions
diff --git a/base/util/CMakeLists.txt b/base/util/CMakeLists.txt
new file mode 100644
index 000000000..b8600ba4c
--- /dev/null
+++ b/base/util/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(util Java)
+
+add_subdirectory(src)
+add_subdirectory(test)
diff --git a/base/util/LICENSE b/base/util/LICENSE
new file mode 100644
index 000000000..e281f4362
--- /dev/null
+++ b/base/util/LICENSE
@@ -0,0 +1,291 @@
+This Program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; version 2 of the License.
+
+This Program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this Program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/base/util/src/CMakeLists.txt b/base/util/src/CMakeLists.txt
new file mode 100644
index 000000000..592e3b59b
--- /dev/null
+++ b/base/util/src/CMakeLists.txt
@@ -0,0 +1,369 @@
+project(pki-cmsutil_java Java)
+
+find_file(JSS_JAR
+ NAMES
+ jss4.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+find_file(LDAPJDK_JAR
+ NAMES
+ ldapjdk.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+find_file(COMMONS_CODEC_JAR
+ NAMES
+ commons-codec.jar
+ PATHS
+ /usr/share/java
+)
+
+find_file(XALAN_JAR
+ NAMES
+ xalan-j2.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+find_file(XERCES_JAR
+ NAMES
+ xerces-j2.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+set(pki-nsutil_java_SRCS
+ netscape/net/TransferProtocolClient.java
+ netscape/net/smtp/SmtpProtocolException.java
+ netscape/net/smtp/SmtpClient.java
+ netscape/net/NetworkClient.java
+ netscape/security/pkcs/ParsingException.java
+ netscape/security/pkcs/PKCS9Attribute.java
+ netscape/security/pkcs/EncodingException.java
+ netscape/security/pkcs/SignerInfo.java
+ netscape/security/pkcs/PKCS10Attribute.java
+ netscape/security/pkcs/PKCS9Attributes.java
+ netscape/security/pkcs/ContentInfo.java
+ netscape/security/pkcs/PKCS10.java
+ netscape/security/pkcs/PKCS10Attributes.java
+ netscape/security/pkcs/PKCS7.java
+ netscape/security/pkcs/PKCS8Key.java
+ netscape/security/x509/OIDName.java
+ netscape/security/x509/CertificateChain.java
+ netscape/security/x509/CertificateVersion.java
+ netscape/security/x509/LdapV3DNStrConverter.java
+ netscape/security/x509/IssuerAlternativeNameExtension.java
+ netscape/security/x509/PolicyMappingsExtension.java
+ netscape/security/x509/CRLExtensions.java
+ netscape/security/x509/X500NameAttrMap.java
+ netscape/security/x509/CertificatePolicySet.java
+ netscape/security/x509/X509Cert.java
+ netscape/security/x509/NSCCommentExtension.java
+ netscape/security/x509/Attribute.java
+ netscape/security/x509/PrivateKeyUsageExtension.java
+ netscape/security/x509/X509CRLImpl.java
+ netscape/security/x509/X500Signer.java
+ netscape/security/x509/CPSuri.java
+ netscape/security/x509/AlgorithmId.java
+ netscape/security/x509/SerialNumber.java
+ netscape/security/x509/X509CertImpl.java
+ netscape/security/x509/CertificatePolicyInfo.java
+ netscape/security/x509/CertException.java
+ netscape/security/x509/CRLNumberExtension.java
+ netscape/security/x509/GeneralNameInterface.java
+ netscape/security/x509/PolicyQualifiers.java
+ netscape/security/x509/AVA.java
+ netscape/security/x509/CertificateX509Key.java
+ netscape/security/x509/RFC822Name.java
+ netscape/security/x509/Extensions.java
+ netscape/security/x509/FreshestCRLExtension.java
+ netscape/security/x509/UserNotice.java
+ netscape/security/x509/ReasonFlags.java
+ netscape/security/x509/InvalidIPAddressException.java
+ netscape/security/x509/IPAddressName.java
+ netscape/security/x509/SubjectKeyIdentifierExtension.java
+ netscape/security/x509/GenericValueConverter.java
+ netscape/security/x509/CRLReasonExtension.java
+ netscape/security/x509/CertificateAlgorithmId.java
+ netscape/security/x509/DisplayText.java
+ netscape/security/x509/CertificateValidity.java
+ netscape/security/x509/PKIXExtensions.java
+ netscape/security/x509/PrintableConverter.java
+ netscape/security/x509/SubjectDirAttributesExtension.java
+ netscape/security/x509/CRLDistributionPoint.java
+ netscape/security/x509/NameConstraintsExtension.java
+ netscape/security/x509/X509AttributeName.java
+ netscape/security/x509/RFC1779StrConverter.java
+ netscape/security/x509/X500Name.java
+ netscape/security/x509/DNSName.java
+ netscape/security/x509/URIName.java
+ netscape/security/x509/CertAndKeyGen.java
+ netscape/security/x509/RevocationReason.java
+ netscape/security/x509/AVAValueConverter.java
+ netscape/security/x509/CRLDistributionPointsExtension.java
+ netscape/security/x509/GeneralSubtree.java
+ netscape/security/x509/X509Key.java
+ netscape/security/x509/PolicyConstraintsExtension.java
+ netscape/security/x509/X509CertInfo.java
+ netscape/security/x509/LdapDNStrConverter.java
+ netscape/security/x509/X509ExtensionException.java
+ netscape/security/x509/AuthorityKeyIdentifierExtension.java
+ netscape/security/x509/NoticeReference.java
+ netscape/security/x509/IA5StringConverter.java
+ netscape/security/x509/UniqueIdentity.java
+ netscape/security/x509/RevokedCertificate.java
+ netscape/security/x509/CertificateExtensions.java
+ netscape/security/x509/HoldInstructionExtension.java
+ netscape/security/x509/IssuingDistributionPoint.java
+ netscape/security/x509/GeneralName.java
+ netscape/security/x509/CertificateIssuerName.java
+ netscape/security/x509/IssuingDistributionPointExtension.java
+ netscape/security/x509/AlgIdDSA.java
+ netscape/security/x509/DeltaCRLIndicatorExtension.java
+ netscape/security/x509/GeneralSubtrees.java
+ netscape/security/x509/BasicConstraintsExtension.java
+ netscape/security/x509/CertAttrSet.java
+ netscape/security/x509/GeneralNamesException.java
+ netscape/security/x509/ACertAttrSet.java
+ netscape/security/x509/Qualifier.java
+ netscape/security/x509/KeyIdentifier.java
+ netscape/security/x509/CertificateSerialNumber.java
+ netscape/security/x509/KeyUsageExtension.java
+ netscape/security/x509/SubjectAlternativeNameExtension.java
+ netscape/security/x509/CertificateSubjectUniqueIdentity.java
+ netscape/security/x509/CertificateSubjectName.java
+ netscape/security/x509/GeneralNames.java
+ netscape/security/x509/Extension.java
+ netscape/security/x509/CertificatePoliciesExtension.java
+ netscape/security/x509/CertificateIssuerExtension.java
+ netscape/security/x509/RDN.java
+ netscape/security/x509/CertificatePolicyMap.java
+ netscape/security/x509/DirStrConverter.java
+ netscape/security/x509/CertificateIssuerUniqueIdentity.java
+ netscape/security/x509/PolicyQualifierInfo.java
+ netscape/security/x509/EDIPartyName.java
+ netscape/security/x509/InvalidityDateExtension.java
+ netscape/security/x509/CertificatePolicyId.java
+ netscape/security/x509/CertParseError.java
+ netscape/security/x509/OIDMap.java
+ netscape/security/x509/PolicyConstraint.java
+ netscape/security/x509/RevokedCertImpl.java
+ netscape/security/x509/OtherName.java
+ netscape/security/util/ASN1CharsetProvider.java
+ netscape/security/util/ASN1CharStrConvMap.java
+ netscape/security/util/BigInt.java
+ netscape/security/util/BitArray.java
+ netscape/security/util/ByteArrayLexOrder.java
+ netscape/security/util/ByteArrayTagOrder.java
+ netscape/security/util/CertPrettyPrint.java
+ netscape/security/util/CrlPrettyPrint.java
+ netscape/security/util/DerEncoder.java
+ netscape/security/util/DerInputBuffer.java
+ netscape/security/util/DerInputStream.java
+ netscape/security/util/DerOutputStream.java
+ netscape/security/util/DerValue.java
+ netscape/security/util/ExtPrettyPrint.java
+ netscape/security/util/IA5Charset.java
+ netscape/security/util/IA5CharsetDecoder.java
+ netscape/security/util/IA5CharsetEncoder.java
+ netscape/security/util/ObjectIdentifier.java
+ netscape/security/util/PrettyPrintFormat.java
+ netscape/security/util/PrettyPrintResources.java
+ netscape/security/util/PrintableCharset.java
+ netscape/security/util/PrintableCharsetDecoder.java
+ netscape/security/util/PrintableCharsetEncoder.java
+ netscape/security/util/PubKeyPrettyPrint.java
+ netscape/security/util/UniversalCharset.java
+ netscape/security/util/UniversalCharsetDecoder.java
+ netscape/security/util/UniversalCharsetEncoder.java
+ netscape/security/provider/DSA.java
+ netscape/security/provider/DSAPrivateKey.java
+ netscape/security/provider/DSAParameters.java
+ netscape/security/provider/DSAPublicKey.java
+ netscape/security/provider/RSAPublicKey.java
+ netscape/security/provider/SHA.java
+ netscape/security/provider/MD5.java
+ netscape/security/provider/DSAParameterGenerator.java
+ netscape/security/provider/CMS.java
+ netscape/security/provider/DSAKeyPairGenerator.java
+ netscape/security/provider/DSAKeyFactory.java
+ netscape/security/provider/Sun.java
+ netscape/security/provider/X509CertificateFactory.java
+ netscape/security/extensions/SubjectInfoAccessExtension.java
+ netscape/security/extensions/GenericASN1Extension.java
+ netscape/security/extensions/NSCertTypeExtension.java
+ netscape/security/extensions/CertificateScopeEntry.java
+ netscape/security/extensions/KerberosName.java
+ netscape/security/extensions/CertificateRenewalWindowExtension.java
+ netscape/security/extensions/PresenceServerExtension.java
+ netscape/security/extensions/OCSPNoCheckExtension.java
+ netscape/security/extensions/CertInfo.java
+ netscape/security/extensions/AccessDescription.java
+ netscape/security/extensions/InhibitAnyPolicyExtension.java
+ netscape/security/extensions/CertificateScopeOfUseExtension.java
+ netscape/security/extensions/AuthInfoAccessExtension.java
+ netscape/security/extensions/ExtendedKeyUsageExtension.java
+ netscape/security/acl/AclImpl.java
+ netscape/security/acl/AllPermissionsImpl.java
+ netscape/security/acl/PrincipalImpl.java
+ netscape/security/acl/AclEntryImpl.java
+ netscape/security/acl/OwnerImpl.java
+ netscape/security/acl/WorldGroupImpl.java
+ netscape/security/acl/GroupImpl.java
+ netscape/security/acl/PermissionImpl.java
+)
+
+set(pki-cmsutil_java_SRCS
+ com/netscape/cmsutil/ldap/LDAPUtil.java
+ com/netscape/cmsutil/xml/XMLObject.java
+ com/netscape/cmsutil/scep/CRSPKIMessage.java
+ com/netscape/cmsutil/util/Cert.java
+ com/netscape/cmsutil/util/Fmt.java
+ com/netscape/cmsutil/util/HMACDigest.java
+ com/netscape/cmsutil/util/Utils.java
+ com/netscape/cmsutil/net/ISocketFactory.java
+ com/netscape/cmsutil/crypto/Token.java
+ com/netscape/cmsutil/crypto/Module.java
+ com/netscape/cmsutil/crypto/CryptoUtil.java
+ com/netscape/cmsutil/password/PlainPasswordReader.java
+ com/netscape/cmsutil/password/IPasswordWriter.java
+ com/netscape/cmsutil/password/IPasswordStore.java
+ com/netscape/cmsutil/password/IPasswordReader.java
+ com/netscape/cmsutil/password/PlainPasswordWriter.java
+ com/netscape/cmsutil/password/PlainPasswordFile.java
+ com/netscape/cmsutil/radius/FramedProtocolAttribute.java
+ com/netscape/cmsutil/radius/TerminationActionAttribute.java
+ com/netscape/cmsutil/radius/NASPortTypeAttribute.java
+ com/netscape/cmsutil/radius/LoginLATServiceAttribute.java
+ com/netscape/cmsutil/radius/VendorSpecificAttribute.java
+ com/netscape/cmsutil/radius/ServiceTypeAttribute.java
+ com/netscape/cmsutil/radius/FramedAppleTalkLinkAttribute.java
+ com/netscape/cmsutil/radius/RadiusConn.java
+ com/netscape/cmsutil/radius/StateAttribute.java
+ com/netscape/cmsutil/radius/Attribute.java
+ com/netscape/cmsutil/radius/ReplyMessageAttribute.java
+ com/netscape/cmsutil/radius/ResponseAuthenticator.java
+ com/netscape/cmsutil/radius/GenericAttribute.java
+ com/netscape/cmsutil/radius/AccessChallenge.java
+ com/netscape/cmsutil/radius/FramedMTUAttribute.java
+ com/netscape/cmsutil/radius/NASPortAttribute.java
+ com/netscape/cmsutil/radius/CallingStationIdAttribute.java
+ com/netscape/cmsutil/radius/UserNameAttribute.java
+ com/netscape/cmsutil/radius/PacketFactory.java
+ com/netscape/cmsutil/radius/UserPasswordAttribute.java
+ com/netscape/cmsutil/radius/NASPacket.java
+ com/netscape/cmsutil/radius/FramedRoutingAttribute.java
+ com/netscape/cmsutil/radius/LoginLATNodeAttribute.java
+ com/netscape/cmsutil/radius/AttributeSet.java
+ com/netscape/cmsutil/radius/RequestAuthenticator.java
+ com/netscape/cmsutil/radius/CHAPPasswordAttribute.java
+ com/netscape/cmsutil/radius/FramedIPNetmaskAttribute.java
+ com/netscape/cmsutil/radius/LoginLATPortAttribute.java
+ com/netscape/cmsutil/radius/CallbackNumberAttribute.java
+ com/netscape/cmsutil/radius/RejectException.java
+ com/netscape/cmsutil/radius/ChallengeException.java
+ com/netscape/cmsutil/radius/NASClassAttribute.java
+ com/netscape/cmsutil/radius/LoginTCPPortAttribute.java
+ com/netscape/cmsutil/radius/IdleTimeoutAttribute.java
+ com/netscape/cmsutil/radius/AccessReject.java
+ com/netscape/cmsutil/radius/SessionTimeoutAttribute.java
+ com/netscape/cmsutil/radius/FramedIPAddressAttribute.java
+ com/netscape/cmsutil/radius/FramedRouteAttribute.java
+ com/netscape/cmsutil/radius/AccessAccept.java
+ com/netscape/cmsutil/radius/FramedAppleTalkNetworkAttribute.java
+ com/netscape/cmsutil/radius/ProxyStateAttribute.java
+ com/netscape/cmsutil/radius/FilterIdAttribute.java
+ com/netscape/cmsutil/radius/NASIdentifierAttribute.java
+ com/netscape/cmsutil/radius/LoginIPHostAttribute.java
+ com/netscape/cmsutil/radius/LoginServiceAttribute.java
+ com/netscape/cmsutil/radius/PortLimitAttribute.java
+ com/netscape/cmsutil/radius/AttributeFactory.java
+ com/netscape/cmsutil/radius/ServerPacket.java
+ com/netscape/cmsutil/radius/FramedAppleTalkZoneAttribute.java
+ com/netscape/cmsutil/radius/CHAPChallengeAttribute.java
+ com/netscape/cmsutil/radius/AccessRequest.java
+ com/netscape/cmsutil/radius/CallerStationIdAttribute.java
+ com/netscape/cmsutil/radius/Packet.java
+ com/netscape/cmsutil/radius/CallbackIdAttribute.java
+ com/netscape/cmsutil/radius/FramedIPXNetworkAttribute.java
+ com/netscape/cmsutil/radius/LoginLATGroupAttribute.java
+ com/netscape/cmsutil/radius/Authenticator.java
+ com/netscape/cmsutil/radius/NASIPAddressAttribute.java
+ com/netscape/cmsutil/radius/FramedCompressionAttribute.java
+ com/netscape/cmsutil/http/ConnectAsync.java
+ com/netscape/cmsutil/http/JssSSLSocketFactory.java
+ com/netscape/cmsutil/http/HttpClient.java
+ com/netscape/cmsutil/http/HttpMessage.java
+ com/netscape/cmsutil/http/HttpRequest.java
+ com/netscape/cmsutil/http/HttpResponse.java
+ com/netscape/cmsutil/http/Http.java
+ com/netscape/cmsutil/http/HttpEofException.java
+ com/netscape/cmsutil/http/HttpProtocolException.java
+ com/netscape/cmsutil/ocsp/Signature.java
+ com/netscape/cmsutil/ocsp/RevokedInfo.java
+ com/netscape/cmsutil/ocsp/TBSRequest.java
+ com/netscape/cmsutil/ocsp/CertID.java
+ com/netscape/cmsutil/ocsp/NameID.java
+ com/netscape/cmsutil/ocsp/KeyHashID.java
+ com/netscape/cmsutil/ocsp/OCSPRequest.java
+ com/netscape/cmsutil/ocsp/Response.java
+ com/netscape/cmsutil/ocsp/GoodInfo.java
+ com/netscape/cmsutil/ocsp/SingleResponse.java
+ com/netscape/cmsutil/ocsp/BasicOCSPResponse.java
+ com/netscape/cmsutil/ocsp/ResponseBytes.java
+ com/netscape/cmsutil/ocsp/OCSPResponse.java
+ com/netscape/cmsutil/ocsp/UnknownInfo.java
+ com/netscape/cmsutil/ocsp/OCSPResponseStatus.java
+ com/netscape/cmsutil/ocsp/CertStatus.java
+ com/netscape/cmsutil/ocsp/ResponseData.java
+ com/netscape/cmsutil/ocsp/Request.java
+ com/netscape/cmsutil/ocsp/ResponderID.java
+)
+
+set(CMAKE_JAVA_INCLUDE_PATH
+ ${LDAPJDK_JAR} ${XALAN_JAR} ${XERCES_JAR}
+ ${JSS_JAR} ${COMMONS_CODEC_JAR})
+
+set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})
+
+# build pki-nsutil
+set(CMAKE_JAR_CLASSES_PREFIX netscape)
+add_jar(pki-nsutil ${pki-nsutil_java_SRCS})
+install_jar(pki-nsutil ${JAVA_JAR_INSTALL_DIR}/pki)
+set(PKI_NSUTIL_JAR ${pki-nsutil_JAR_FILE} CACHE INTERNAL "pki-nsutil jar file")
+
+# build pki-cmsutil
+set(CMAKE_JAR_CLASSES_PREFIX com/netscape/cmsutil)
+add_jar(pki-cmsutil ${pki-cmsutil_java_SRCS})
+add_dependencies(pki-cmsutil pki-nsutil)
+install_jar(pki-cmsutil ${JAVA_JAR_INSTALL_DIR}/pki)
+set(PKI_CMSUTIL_JAR ${pki-cmsutil_JAR_FILE} CACHE INTERNAL "pki-cmsutil jar file")
+
+create_javadoc(pki-util-${APPLICATION_VERSION}
+ PACKAGES com.netscape.cmsutil.crypto
+ com.netscape.cmsutil.http
+ com.netscape.cmsutil.ldap
+ com.netscape.cmsutil.net
+ com.netscape.cmsutil.ocsp
+ com.netscape.cmsutil.password
+ com.netscape.cmsutil.radius
+ com.netscape.cmsutil.scep
+ com.netscape.cmsutil.util
+ com.netscape.cmsutil.xml
+ SOURCEPATH ${CMAKE_CURRENT_SOURCE_DIR}
+ CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+ WINDOWTITLE "pki-util"
+ WINDOWTITLE "pki-util"
+ DOCTITLE "<h1>dogtag</h1>"
+ AUTHOR TRUE
+ USE TRUE
+ VERSION TRUE
+)
+add_dependencies(pki-util-${APPLICATION_VERSION}_javadoc pki-cmsutil)
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
new file mode 100644
index 000000000..bf8a9cfc1
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -0,0 +1,1292 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.crypto;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.pkcs.PKCS10;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.CertificateAlgorithmId;
+import netscape.security.x509.CertificateChain;
+import netscape.security.x509.CertificateExtensions;
+import netscape.security.x509.CertificateIssuerName;
+import netscape.security.x509.CertificateSerialNumber;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.CertificateValidity;
+import netscape.security.x509.CertificateVersion;
+import netscape.security.x509.CertificateX509Key;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X500Signer;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.NoSuchTokenException;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.crypto.Algorithm;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoStore;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.InternalCertificate;
+import org.mozilla.jss.crypto.InvalidKeyFormatException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.NoSuchItemOnTokenException;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.Signature;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs11.PK11ECPublicKey;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.util.Base64OutputStream;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Cert;
+import com.netscape.cmsutil.util.Utils;
+
+public class CryptoUtil {
+
+ public static final String CERTREQ_BEGIN_HEADING = "-----BEGIN CERTIFICATE REQUEST-----";
+ public static final String CERTREQ_END_HEADING = "-----END CERTIFICATE REQUEST-----";
+ public static final int LINE_COUNT = 76;
+ public static final String CERT_BEGIN_HEADING = "-----BEGIN CERTIFICATE-----";
+ public static final String CERT_END_HEADING = "-----END CERTIFICATE-----";
+
+ /*
+ * encodes cert
+ */
+ // private static BASE64Encoder mEncoder = new BASE64Encoder();
+ public static String toMIME64(X509CertImpl cert) {
+ try {
+ return "-----BEGIN CERTIFICATE-----\n"
+ // + mEncoder.encodeBuffer(cert.getEncoded())
+ + Utils.base64encode(cert.getEncoded())
+ + "-----END CERTIFICATE-----\n";
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public static boolean arraysEqual(byte[] bytes, byte[] ints) {
+ if (bytes == null || ints == null) {
+ return false;
+ }
+
+ if (bytes.length != ints.length) {
+ return false;
+ }
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != ints[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Retrieves handle to a JSS token.
+ */
+ public static CryptoToken getTokenByName(String token)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken t = null;
+
+ if (token.equals("internal")) {
+ t = cm.getInternalKeyStorageToken();
+ } else {
+ t = cm.getTokenByName(token);
+ }
+ return t;
+ }
+
+ /**
+ * Generates a RSA key pair.
+ */
+ public static KeyPair generateRSAKeyPair(String token, int keysize)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+ KeyPairGenerator g = t.getKeyPairGenerator(KeyPairAlgorithm.RSA);
+
+ g.initialize(keysize);
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ public static boolean isECCKey(X509Key key) {
+ String keyAlgo = key.getAlgorithm();
+ if (keyAlgo.equals("EC") ||
+ keyAlgo.equals("OID.1.2.840.10045.44")) { // ECC
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Generates an ecc key pair.
+ */
+ public static KeyPair generateECCKeyPair(String token, int keysize)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, keysize, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(String token, int keysize,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+
+ KeyPairAlgorithm alg = KeyPairAlgorithm.EC;
+ KeyPairGenerator g = t.getKeyPairGenerator(alg);
+
+ g.setKeyPairUsages(usage_ops, usage_mask);
+ g.initialize(keysize);
+
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ /**
+ * Generates an ecc key pair by curve name
+ */
+ public static KeyPair generateECCKeyPair(String token, String curveName)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, curveName, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(CryptoToken token, String curveName)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, curveName, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(String token, String curveName,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+ return generateECCKeyPair(t, curveName, usage_ops, usage_mask);
+ }
+
+ public static KeyPair generateECCKeyPair(CryptoToken token, String curveName,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ KeyPairAlgorithm alg = KeyPairAlgorithm.EC;
+ KeyPairGenerator g = token.getKeyPairGenerator(alg);
+
+ g.setKeyPairUsages(usage_ops, usage_mask);
+
+ System.out.println("CryptoUtil: generateECCKeyPair: curve = " + curveName);
+ int curveCode = 0;
+ try {
+ curveCode = g.getCurveCodeByName(curveName);
+ } catch (Exception e) {
+ System.out.println("CryptoUtil: generateECCKeyPair: " + e.toString());
+ throw new NoSuchAlgorithmException();
+ }
+ g.initialize(curveCode);
+
+ System.out.println("CryptoUtil: generateECCKeyPair: after KeyPairGenerator initialize with:" + curveName);
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ public static byte[] getModulus(PublicKey pubk) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ return rsaKey.getModulus().toByteArray();
+ }
+
+ public static byte[] getPublicExponent(PublicKey pubk) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ return rsaKey.getPublicExponent().toByteArray();
+ }
+
+ public static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)));
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ public static byte[] base64Decode(String s) throws IOException {
+ // BASE64Decoder base64 = new BASE64Decoder();
+ // byte[] d = base64.decodeBuffer(s);
+ byte[] d = Utils.base64decode(s);
+
+ return d;
+ }
+
+ /*
+ * formats a cert request
+ */
+ public static String reqFormat(String content) {
+ String result = CERTREQ_BEGIN_HEADING + "\n";
+
+ while (content.length() >= LINE_COUNT) {
+ result = result + content.substring(0, LINE_COUNT) + "\n";
+ content = content.substring(LINE_COUNT);
+ }
+ if (content.length() > 0) {
+ result = result + content + "\n" + CERTREQ_END_HEADING;
+ } else {
+ result = result + CERTREQ_END_HEADING;
+ }
+
+ return result;
+ }
+
+ public static String getPKCS10FromKey(String dn,
+ byte modulus[], byte exponent[], byte prikdata[])
+ throws IOException,
+ InvalidKeyException,
+ TokenException,
+ NoSuchProviderException,
+ CertificateException,
+ SignatureException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException {
+ X509Key x509key = getPublicX509Key(modulus, exponent);
+ PrivateKey prik = findPrivateKeyFromID(prikdata);
+ PKCS10 pkcs10 = createCertificationRequest(dn, x509key, prik);
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+ pkcs10.print(ps);
+ return bs.toString();
+ }
+
+ public static String getPKCS10FromKey(String dn,
+ byte modulus[], byte exponent[], byte prikdata[], String alg)
+ throws IOException,
+ InvalidKeyException,
+ TokenException,
+ NoSuchProviderException,
+ CertificateException,
+ SignatureException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException {
+ X509Key x509key = getPublicX509Key(modulus, exponent);
+ PrivateKey prik = findPrivateKeyFromID(prikdata);
+ PKCS10 pkcs10 = createCertificationRequest(dn, x509key, prik, alg);
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+ pkcs10.print(ps);
+ return bs.toString();
+ }
+
+ /*
+ * formats a cert
+ */
+ public static String certFormat(String content) {
+ if (content == null || content.length() == 0) {
+ return "";
+ }
+ String result = CERT_BEGIN_HEADING + "\n";
+
+ while (content.length() >= LINE_COUNT) {
+ result = result + content.substring(0, LINE_COUNT) + "\n";
+ content = content.substring(LINE_COUNT);
+ }
+ if (content.length() > 0) {
+ result = result + content + "\n" + CERT_END_HEADING;
+ } else {
+ result = result + CERT_END_HEADING;
+ }
+
+ return result;
+ }
+
+ /**
+ * strips out the begin and end certificate brackets
+ *
+ * @param s the string potentially bracketed with
+ * "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----"
+ * @return string without the brackets
+ */
+ public static String stripCertBrackets(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if (s.startsWith(CERT_BEGIN_HEADING) && s.endsWith(CERT_END_HEADING)) {
+ return (s.substring(27, (s.length() - 25)));
+ }
+
+ // To support Thawte's header and footer
+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----"))
+ && (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) {
+ return (s.substring(35, (s.length() - 33)));
+ }
+
+ return s;
+ }
+
+ public static String normalizeCertAndReq(String s) {
+ if (s == null) {
+ return s;
+ }
+ s = s.replaceAll("-----BEGIN CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----BEGIN NEW CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----END CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----END NEW CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----BEGIN CERTIFICATE-----", "");
+ s = s.replaceAll("-----END CERTIFICATE-----", "");
+
+ StringBuffer sb = new StringBuffer();
+ StringTokenizer st = new StringTokenizer(s, "\r\n ");
+
+ while (st.hasMoreTokens()) {
+ String nextLine = st.nextToken();
+
+ nextLine = nextLine.trim();
+ if (nextLine.equals("-----BEGIN CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END NEW CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----BEGIN CERTIFICATE-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END CERTIFICATE-----")) {
+ continue;
+ }
+ sb.append(nextLine);
+ }
+ return sb.toString();
+ }
+
+ public static String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\n') {
+ continue;
+ } else if (s.charAt(i) == '\r') {
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ public static void importCertificateChain(String certchain)
+ throws IOException,
+ CryptoManager.NotInitializedException,
+ TokenException,
+ CertificateEncodingException,
+ CertificateException {
+ byte[] blah = base64Decode(certchain);
+ CryptoManager manager = CryptoManager.getInstance();
+ PKCS7 pkcs7 = null;
+ try {
+ // try PKCS7 first
+ pkcs7 = new PKCS7(blah);
+ } catch (Exception e) {
+ }
+ X509Certificate cert = null;
+ if (pkcs7 == null) {
+ cert = manager.importCACertPackage(blah);
+ } else {
+ java.security.cert.X509Certificate certsInP7[] =
+ pkcs7.getCertificates();
+ if (certsInP7 == null) {
+ cert = manager.importCACertPackage(blah);
+ } else {
+ for (int i = 0; i < certsInP7.length; i++) {
+ // import P7 one by one
+ cert = manager.importCACertPackage(certsInP7[i].getEncoded());
+ }
+ }
+ }
+ X509Certificate[] certchains =
+ CryptoManager.getInstance().buildCertificateChain(cert);
+
+ if (certchains != null) {
+ cert = certchains[certchains.length - 1];
+ }
+ InternalCertificate icert = (InternalCertificate) cert;
+ icert.setSSLTrust(InternalCertificate.TRUSTED_CA
+ | InternalCertificate.TRUSTED_CLIENT_CA
+ | InternalCertificate.VALID_CA);
+ }
+
+ public static SEQUENCE parseCRMFMsgs(byte cert_request[])
+ throws IOException, InvalidBERException {
+ ByteArrayInputStream crmfBlobIn =
+ new ByteArrayInputStream(cert_request);
+ SEQUENCE crmfMsgs = (SEQUENCE)
+ new SEQUENCE.OF_Template(new CertReqMsg.Template()).decode(
+ crmfBlobIn);
+ return crmfMsgs;
+ }
+
+ public static X509Key getX509KeyFromCRMFMsgs(SEQUENCE crmfMsgs)
+ throws IOException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidKeyFormatException {
+ int nummsgs = crmfMsgs.size();
+ if (nummsgs <= 0) {
+ throw new IOException("invalid certificate requests");
+ }
+ CertReqMsg msg = (CertReqMsg) crmfMsgs.elementAt(0);
+ CertRequest certreq = msg.getCertReq();
+ CertTemplate certTemplate = certreq.getCertTemplate();
+ SubjectPublicKeyInfo spkinfo = certTemplate.getPublicKey();
+ PublicKey pkey = spkinfo.toPublicKey();
+ X509Key x509key = convertPublicKeyToX509Key(pkey);
+ return x509key;
+ }
+
+ public static X509Key getPublicX509Key(byte modulus[], byte exponent[])
+ throws InvalidKeyException {
+ return new netscape.security.provider.RSAPublicKey(new BigInt(modulus),
+ new BigInt(exponent));
+ }
+
+ public static X509Key getPublicX509ECCKey(byte encoded[])
+ throws InvalidKeyException {
+ try {
+ return X509Key.parse(new DerValue(encoded));
+ } catch (IOException e) {
+ throw new InvalidKeyException();
+ }
+ }
+
+ public static X509Key convertPublicKeyToX509Key(PublicKey pubk)
+ throws InvalidKeyException {
+ X509Key xKey;
+
+ if (pubk instanceof RSAPublicKey) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ xKey = new netscape.security.provider.RSAPublicKey(
+ new BigInt(rsaKey.getModulus()),
+ new BigInt(rsaKey.getPublicExponent()));
+ } else if (pubk instanceof PK11ECPublicKey) {
+ byte encoded[] = pubk.getEncoded();
+ xKey = CryptoUtil.getPublicX509ECCKey(encoded);
+ } else {
+ // Assert.assert(pubk instanceof DSAPublicKey);
+ DSAPublicKey dsaKey = (DSAPublicKey) pubk;
+ DSAParams params = dsaKey.getParams();
+
+ xKey = new netscape.security.provider.DSAPublicKey(dsaKey.getY(),
+ params.getP(), params.getQ(), params.getG());
+ }
+ return xKey;
+ }
+
+ public static String getSubjectName(SEQUENCE crmfMsgs)
+ throws IOException {
+ int nummsgs = crmfMsgs.size();
+ if (nummsgs <= 0) {
+ throw new IOException("invalid certificate requests");
+ }
+ CertReqMsg msg = (CertReqMsg) crmfMsgs.elementAt(0);
+ CertRequest certreq = msg.getCertReq();
+ CertTemplate certTemplate = certreq.getCertTemplate();
+ Name n = certTemplate.getSubject();
+ ByteArrayOutputStream subjectEncStream = new ByteArrayOutputStream();
+ n.encode(subjectEncStream);
+
+ byte[] b = subjectEncStream.toByteArray();
+ X500Name subject = new X500Name(b);
+ return subject.toString();
+ }
+
+ /**
+ * Creates a Certificate template.
+ */
+ public static X509CertInfo createX509CertInfo(KeyPair pair,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ return createX509CertInfo(convertPublicKeyToX509Key(pair.getPublic()),
+ serialno, issuername, subjname, notBefore, notAfter);
+ }
+
+ public static X509CertInfo createX509CertInfo(PublicKey publickey,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ return createX509CertInfo(convertPublicKeyToX509Key(publickey), serialno,
+ issuername, subjname, notBefore, notAfter);
+ }
+
+ public static X509CertInfo createX509CertInfo(X509Key x509key,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ // set default; use the other call with "alg" to set algorithm
+ String alg = "SHA256withRSA";
+ try {
+ return createX509CertInfo(x509key, serialno, issuername, subjname, notBefore, notAfter, alg);
+ } catch (NoSuchAlgorithmException ex) {
+ // for those that calls the old call without alg
+ throw new CertificateException("createX509CertInfo old call should not be here");
+ }
+ }
+
+ public static X509CertInfo createX509CertInfo(X509Key x509key,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter, String alg)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException,
+ NoSuchAlgorithmException {
+ X509CertInfo info = new X509CertInfo();
+
+ info.set(X509CertInfo.VERSION, new
+ CertificateVersion(CertificateVersion.V3));
+ info.set(X509CertInfo.SERIAL_NUMBER, new
+ CertificateSerialNumber(serialno));
+ info.set(X509CertInfo.ISSUER, new
+ CertificateIssuerName(new X500Name(issuername)));
+ info.set(X509CertInfo.SUBJECT, new
+ CertificateSubjectName(new X500Name(subjname)));
+ info.set(X509CertInfo.VALIDITY, new
+ CertificateValidity(notBefore, notAfter));
+ info.set(X509CertInfo.ALGORITHM_ID, new
+ CertificateAlgorithmId(AlgorithmId.get(alg)));
+ info.set(X509CertInfo.KEY, new CertificateX509Key(x509key));
+ info.set(X509CertInfo.EXTENSIONS, new CertificateExtensions());
+ return info;
+ }
+
+ public static X509CertImpl signECCCert(PrivateKey privateKey,
+ X509CertInfo certInfo)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ // set default; use the other call with "alg" to specify algorithm
+ String alg = "SHA256withEC";
+ return signECCCert(privateKey, certInfo, alg);
+ }
+
+ public static X509CertImpl signECCCert(PrivateKey privateKey,
+ X509CertInfo certInfo, String alg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ return signCert(privateKey, certInfo,
+ Cert.mapAlgorithmToJss(alg));
+ }
+
+ /**
+ * Signs certificate.
+ */
+ public static X509CertImpl signCert(PrivateKey privateKey,
+ X509CertInfo certInfo, String alg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ return signCert(privateKey, certInfo,
+ Cert.mapAlgorithmToJss(alg));
+ }
+
+ public static X509CertImpl signCert(PrivateKey privateKey,
+ X509CertInfo certInfo, SignatureAlgorithm sigAlg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+
+ DerInputStream ds = new DerInputStream(ASN1Util.encode(sigAlg.toOID()));
+ ObjectIdentifier sigAlgOID = new ObjectIdentifier(ds);
+ AlgorithmId aid = new AlgorithmId(sigAlgOID);
+ certInfo.set(X509CertInfo.ALGORITHM_ID,
+ new CertificateAlgorithmId(aid));
+
+ org.mozilla.jss.crypto.PrivateKey priKey =
+ (org.mozilla.jss.crypto.PrivateKey) privateKey;
+ CryptoToken token = priKey.getOwningToken();
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ certInfo.encode(tmp);
+ Signature signer = token.getSignatureContext(sigAlg);
+
+ signer.initSign(priKey);
+ signer.update(tmp.toByteArray());
+ byte signed[] = signer.sign();
+
+ aid.encode(tmp);
+ tmp.putBitString(signed);
+ out.write(DerValue.tag_Sequence, tmp);
+ X509CertImpl signedCert = new X509CertImpl(out.toByteArray());
+
+ return signedCert;
+ }
+
+ /**
+ * Creates a PKCS#10 request.
+ */
+ public static PKCS10 createCertificationRequest(String subjectName,
+ X509Key pubk, PrivateKey prik)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ // give default
+ String alg = "SHA256withRSA";
+ if (isECCKey(pubk)) {
+ alg = "SHA256withEC";
+ }
+ return createCertificationRequest(subjectName, pubk, prik, alg);
+ }
+
+ public static PKCS10 createCertificationRequest(String subjectName,
+ X509Key pubk, PrivateKey prik, String alg)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ X509Key key = pubk;
+ java.security.Signature sig = java.security.Signature.getInstance(alg,
+ "Mozilla-JSS");
+
+ sig.initSign(prik);
+ PKCS10 pkcs10 = new PKCS10(key);
+ X500Name name = new X500Name(subjectName);
+ X500Signer signer = new X500Signer(sig, name);
+
+ pkcs10.encodeAndSign(signer);
+ return pkcs10;
+ }
+
+ /**
+ * Creates a PKCS#10 request.
+ */
+ public static PKCS10 createCertificationRequest(String subjectName,
+ KeyPair keyPair)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ String alg;
+ PublicKey pubk = keyPair.getPublic();
+ X509Key key = convertPublicKeyToX509Key(pubk);
+ if (pubk instanceof RSAPublicKey) {
+ alg = "SHA256withRSA";
+ } else if (isECCKey(key)) {
+ alg = "SHA256withEC";
+ } else {
+ // Assert.assert(pubk instanceof DSAPublicKey);
+ alg = "DSA";
+ }
+ return createCertificationRequest(subjectName, keyPair, alg);
+ }
+
+ public static PKCS10 createCertificationRequest(String subjectName,
+ KeyPair keyPair, String alg)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ PublicKey pubk = keyPair.getPublic();
+ X509Key key = convertPublicKeyToX509Key(pubk);
+
+ java.security.Signature sig = java.security.Signature.getInstance(alg,
+ "Mozilla-JSS");
+
+ sig.initSign(keyPair.getPrivate());
+
+ PKCS10 pkcs10 = new PKCS10(key);
+
+ X500Name name = new X500Name(subjectName);
+ X500Signer signer = new X500Signer(sig, name);
+
+ pkcs10.encodeAndSign(signer);
+
+ return pkcs10;
+ }
+
+ public static void unTrustCert(InternalCertificate cert) {
+ // remove TRUSTED_CA
+ int flag = cert.getSSLTrust();
+
+ flag ^= InternalCertificate.VALID_CA;
+ cert.setSSLTrust(flag);
+ }
+
+ /**
+ * Trusts a certificate by nickname.
+ */
+ public static void trustCertByNickname(String nickname)
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate certs[] = cm.findCertsByNickname(nickname);
+
+ if (certs == null) {
+ return;
+ }
+ for (int i = 0; i < certs.length; i++) {
+ trustCert((InternalCertificate) certs[i]);
+ }
+ }
+
+ /**
+ * Trusts a certificate.
+ */
+ public static void trustCert(InternalCertificate cert) {
+ int flag = InternalCertificate.VALID_CA | InternalCertificate.TRUSTED_CA
+ | InternalCertificate.USER
+ | InternalCertificate.TRUSTED_CLIENT_CA;
+
+ cert.setSSLTrust(flag);
+ cert.setObjectSigningTrust(flag);
+ cert.setEmailTrust(flag);
+ }
+
+ /**
+ * To certificate server point of view, SSL trust is
+ * what we referring.
+ */
+ public static boolean isCertTrusted(InternalCertificate cert) {
+ if (isTrust(cert.getSSLTrust()) && isTrust(cert.getObjectSigningTrust())
+ && isTrust(cert.getEmailTrust())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean isTrust(int flag) {
+ if (((flag & InternalCertificate.VALID_CA) > 0)
+ && ((flag & InternalCertificate.TRUSTED_CA) > 0)
+ && ((flag & InternalCertificate.USER) > 0)
+ && ((flag & InternalCertificate.TRUSTED_CLIENT_CA) > 0)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Generates a symmetric key.
+ */
+ public static SymmetricKey generateKey(CryptoToken token,
+ KeyGenAlgorithm alg)
+ throws TokenException, NoSuchAlgorithmException,
+ IllegalStateException {
+ try {
+ KeyGenerator kg = token.getKeyGenerator(alg);
+
+ return kg.generate();
+ } catch (CharConversionException e) {
+ throw new RuntimeException(
+ "CharConversionException while generating symmetric key");
+ }
+ }
+
+ /**
+ * Compares 2 byte arrays to see if they are the same.
+ */
+ public static boolean compare(byte src[], byte dest[]) {
+ if (src != null && dest != null) {
+ if (src.length == dest.length) {
+ boolean matched = true;
+
+ for (int i = 0; i < src.length; i++) {
+ if (src[i] != dest[i]) {
+ matched = false;
+ }
+ }
+ if (matched) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static String byte2string(byte id[]) {
+ return new BigInteger(id).toString(16);
+ }
+
+ public static byte[] string2byte(String id) {
+ return (new BigInteger(id, 16)).toByteArray();
+ }
+
+ /**
+ * Retrieves a private key from a unique key ID.
+ */
+ public static PrivateKey findPrivateKeyFromID(byte id[])
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ @SuppressWarnings("unchecked")
+ Enumeration<CryptoToken> enums = cm.getAllTokens();
+
+ while (enums.hasMoreElements()) {
+ CryptoToken token = enums.nextElement();
+ CryptoStore store = token.getCryptoStore();
+ PrivateKey keys[] = store.getPrivateKeys();
+
+ if (keys != null) {
+ for (int i = 0; i < keys.length; i++) {
+ if (compare(keys[i].getUniqueID(), id)) {
+ return keys[i];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves all user certificates from all tokens.
+ */
+ public static X509CertImpl[] getAllUserCerts()
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ Vector<X509CertImpl> certs = new Vector<X509CertImpl>();
+ CryptoManager cm = CryptoManager.getInstance();
+ @SuppressWarnings("unchecked")
+ Enumeration<CryptoToken> enums = cm.getAllTokens();
+
+ while (enums.hasMoreElements()) {
+ CryptoToken token = (CryptoToken) enums.nextElement();
+
+ CryptoStore store = token.getCryptoStore();
+ org.mozilla.jss.crypto.X509Certificate list[] = store.getCertificates();
+
+ for (int i = 0; i < list.length; i++) {
+ try {
+ @SuppressWarnings("unused")
+ PrivateKey key = cm.findPrivKeyByCert(list[i]); // check for errors
+ X509CertImpl impl = null;
+
+ try {
+ impl = new X509CertImpl(list[i].getEncoded());
+ } catch (CertificateException e) {
+ continue;
+ }
+ certs.addElement(impl);
+ } catch (TokenException e) {
+ continue;
+ } catch (ObjectNotFoundException e) {
+ continue;
+ }
+ }
+ }
+ if (certs.size() == 0) {
+ return null;
+ } else {
+ X509CertImpl c[] = new X509CertImpl[certs.size()];
+
+ certs.copyInto(c);
+ return c;
+ }
+ }
+
+ /**
+ * Deletes a private key.
+ */
+ public static void deletePrivateKey(PrivateKey prikey)
+ throws CryptoManager.NotInitializedException, TokenException {
+
+ try {
+ CryptoToken token = prikey.getOwningToken();
+ CryptoStore store = token.getCryptoStore();
+
+ store.deletePrivateKey(prikey);
+ } catch (NoSuchItemOnTokenException e) {
+ }
+ }
+
+ /**
+ * Retrieves a private key by nickname.
+ */
+ public static PrivateKey getPrivateKey(String nickname)
+ throws CryptoManager.NotInitializedException, TokenException {
+ try {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate cert = cm.findCertByNickname(nickname);
+ org.mozilla.jss.crypto.PrivateKey prikey = cm.findPrivKeyByCert(cert);
+
+ return prikey;
+ } catch (ObjectNotFoundException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Deletes all certificates by a nickname.
+ */
+ public static void deleteAllCertificates(String nickname)
+ throws CryptoManager.NotInitializedException, TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate certs[] = cm.findCertsByNickname(nickname);
+
+ if (certs == null) {
+ return;
+ }
+ for (int i = 0; i < certs.length; i++) {
+ try {
+ X509Certificate cert = certs[i];
+ org.mozilla.jss.crypto.PrivateKey prikey = cm.findPrivKeyByCert(
+ cert);
+ CryptoToken token = prikey.getOwningToken();
+ CryptoStore store = token.getCryptoStore();
+
+ store.deleteCert(cert);
+ } catch (NoSuchItemOnTokenException e) {
+ } catch (ObjectNotFoundException e) {
+ }
+ }
+ }
+
+ /**
+ * Imports a PKCS#7 certificate chain that includes the user
+ * certificate, and trusts the certificate.
+ */
+ public static X509Certificate importUserCertificateChain(String c,
+ String nickname)
+ throws CryptoManager.NotInitializedException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CertificateEncodingException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate cert = cm.importCertPackage(c.getBytes(), nickname);
+
+ trustCertByNickname(nickname);
+ return cert;
+ }
+
+ /**
+ * Imports a user certificate, and trusts the certificate.
+ */
+ public static void importUserCertificate(X509CertImpl cert, String nickname)
+ throws CryptoManager.NotInitializedException,
+ CertificateEncodingException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException {
+ CryptoManager cm = CryptoManager.getInstance();
+
+ cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ trustCertByNickname(nickname);
+ }
+
+ public static void importUserCertificate(X509CertImpl cert, String nickname,
+ boolean trust)
+ throws CryptoManager.NotInitializedException,
+ CertificateEncodingException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException {
+ CryptoManager cm = CryptoManager.getInstance();
+
+ cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ if (trust)
+ trustCertByNickname(nickname);
+ }
+
+ public static java.security.cert.X509Certificate[] getX509CertificateFromPKCS7(byte[] b) throws IOException {
+ ByteArrayInputStream bis = new ByteArrayInputStream(b);
+ CertificateChain certchain = new CertificateChain();
+
+ certchain.decode(bis);
+ java.security.cert.X509Certificate[] certs = certchain.getChain();
+
+ return certs;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+ throws IOException, InvalidBERException, InvalidKeyException, IllegalStateException,
+ NoSuchAlgorithmException, InvalidAlgorithmParameterException, NotInitializedException, TokenException,
+ IllegalBlockSizeException, BadPaddingException {
+ EncryptedContentInfo cInfo = null;
+ String unwrappedData = null;
+
+ //We have to do this to get the decoding to work.
+ @SuppressWarnings("unused")
+ PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+ Password pass = new Password(recoveryPassphrase.toCharArray());
+ PasswordConverter passConverter = new
+ PasswordConverter();
+
+ byte[] encoded = Utils.base64decode(wrappedRecoveredKey);
+
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+ cInfo = (EncryptedContentInfo)
+ new EncryptedContentInfo.Template().decode(inStream);
+
+ byte[] decodedData = cInfo.decrypt(pass, passConverter);
+
+ unwrappedData = Utils.base64encode(decodedData);
+
+ return unwrappedData;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
+ SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException,
+ BadPaddingException,
+ IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ Cipher decryptor = token.getCipherContext(alg);
+ decryptor.initDecrypt(recoveryKey, IV);
+ byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
+ String unwrappedS = Utils.base64encode(unwrappedData);
+
+ return unwrappedS;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk,
+ EncryptionAlgorithm alg)
+ throws NoSuchAlgorithmException, TokenException, InvalidKeyException,
+ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
+ byte[] wrappedPassphrase = null;
+ Cipher encryptor = null;
+
+ encryptor = token.getCipherContext(alg);
+
+ if (encryptor != null) {
+ encryptor.initEncrypt(sk, IV);
+ wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
+ } else {
+ throw new IOException("Failed to create cipher");
+ }
+
+ return wrappedPassphrase;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert,
+ SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidAlgorithmParameterException {
+ byte transport[] = Utils.base64decode(transportCert);
+ X509Certificate tcert = manager.importCACertPackage(transport);
+ KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+ rsaWrap.initWrap(tcert.getPublicKey(), null);
+ byte session_data[] = rsaWrap.wrap(sk);
+ return session_data;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
+ SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, IVParameterSpec IV) throws TokenException,
+ CharConversionException,
+ NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
+ CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
+ BadPaddingException, InvalidBERException {
+ byte[] key_data = null;
+
+ //generate session key
+ SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg);
+
+ if (passphrase != null) {
+ key_data = wrapPassphrase(token, passphrase, IV, sk, EncryptionAlgorithm.DES3_CBC_PAD);
+ } else {
+ // wrap payload using session key
+ KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ wrapper1.initWrap(sk, IV);
+ key_data = wrapper1.wrap(vek);
+ }
+
+ // wrap session key using transport key
+ byte[] session_data = wrapSymmetricKey(manager, token, transportCert, sk);
+
+ // create PKIArchiveOptions structure
+ AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
+ new OCTET_STRING(IV.getIV()));
+ EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
+ new BIT_STRING(key_data, 0));
+ EncryptedKey key = new EncryptedKey(encValue);
+ PKIArchiveOptions opt = new PKIArchiveOptions(key);
+
+ byte[] encoded = null;
+
+ //Let's make sure we can decode the encoded PKIArchiveOptions..
+ ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+
+ opt.encode(oStream);
+
+ encoded = oStream.toByteArray();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+
+ @SuppressWarnings("unused")
+ PKIArchiveOptions options = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(inStream);
+
+ return encoded;
+ }
+}
+
+// START ENABLE_ECC
+// This following can be removed when JSS with ECC capability
+// is integrated.
+class CryptoAlgorithm extends Algorithm {
+ protected CryptoAlgorithm(int oidIndex, String name) {
+ super(oidIndex, name);
+ }
+}
+
+class CryptoKeyPairAlgorithm extends KeyPairAlgorithm {
+ protected CryptoKeyPairAlgorithm(int oidIndex, String name, Algorithm algFamily) {
+ super(oidIndex, name, algFamily);
+ }
+}
+
+class CryptoSignatureAlgorithm extends SignatureAlgorithm {
+ protected CryptoSignatureAlgorithm(int oidIndex, String name,
+ SignatureAlgorithm signingAlg, DigestAlgorithm digestAlg,
+ OBJECT_IDENTIFIER oid) {
+ super(oidIndex, name, signingAlg, digestAlg, oid);
+ }
+}
+// END ENABLE_ECC
diff --git a/base/util/src/com/netscape/cmsutil/crypto/Module.java b/base/util/src/com/netscape/cmsutil/crypto/Module.java
new file mode 100644
index 000000000..bf4a7fe73
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/crypto/Module.java
@@ -0,0 +1,75 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.crypto;
+
+import java.util.Vector;
+
+import org.mozilla.jss.crypto.CryptoToken;
+
+public class Module {
+ // Common Name is the name given when module is added
+ private String mCommonName = "";
+ // User friendly name is the name to be displayed on panel
+ private String mUserFriendlyName = "";
+ private String mImagePath = "";
+ // a Vector of Tokens
+ private Vector<Token> mTokens = null;
+ private boolean mFound = false;
+
+ public Module(String name, String printName) {
+ mCommonName = name;
+ mUserFriendlyName = printName;
+ mTokens = new Vector<Token>();
+ }
+
+ public Module(String name, String printName, String image) {
+ mCommonName = name;
+ mUserFriendlyName = printName;
+ mImagePath = image;
+ mTokens = new Vector<Token>();
+ }
+
+ public void addToken(CryptoToken t) {
+ Token token = new Token(t);
+ mTokens.addElement(token);
+ }
+
+ public String getCommonName() {
+ return mCommonName;
+ }
+
+ public String getUserFriendlyName() {
+ return mUserFriendlyName;
+ }
+
+ public String getImagePath() {
+ return mImagePath;
+ }
+
+ public boolean isFound() {
+ return mFound;
+ }
+
+ public void setFound(boolean isFound) {
+ mFound = isFound;
+ }
+
+ public Vector<Token> getTokens() {
+ return mTokens;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/crypto/Token.java b/base/util/src/com/netscape/cmsutil/crypto/Token.java
new file mode 100644
index 000000000..c6f5a5e3c
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/crypto/Token.java
@@ -0,0 +1,57 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.crypto;
+
+import org.mozilla.jss.crypto.CryptoToken;
+
+public class Token {
+ CryptoToken mToken;
+
+ public Token(CryptoToken token) {
+ mToken = token;
+ }
+
+ public String getNickName() {
+ String nickName = "";
+ try {
+ nickName = mToken.getName();
+ } catch (Exception e) {
+ }
+ return nickName;
+ }
+
+ public boolean isLoggedIn() {
+ boolean isLoggedIn = false;
+ try {
+ isLoggedIn = mToken.isLoggedIn();
+ } catch (Exception e) {
+ }
+
+ return isLoggedIn;
+ }
+
+ public boolean isPresent() {
+ boolean isPresent = false;
+ try {
+ isPresent = mToken.isPresent();
+ } catch (Exception e) {
+ }
+
+ return isPresent;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java b/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java
new file mode 100644
index 000000000..ca230ca21
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java
@@ -0,0 +1,46 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.net.SocketException;
+
+import com.netscape.cmsutil.net.ISocketFactory;
+
+public class ConnectAsync extends Thread {
+ String host = null;
+ int port = 0;
+ ISocketFactory obj = null;
+
+ public ConnectAsync(ISocketFactory sock, String host, int port) {
+ super();
+ this.host = host;
+ this.port = port;
+ this.obj = sock;
+ setName("ConnectAsync");
+ }
+
+ public void run() {
+ try {
+ obj.makeSocket(host, port);
+ } catch (SocketException e) {
+ // Stop throwing exception
+ } catch (Exception e) {
+ // Stop throwing exception
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/Http.java b/base/util/src/com/netscape/cmsutil/http/Http.java
new file mode 100644
index 000000000..2cda7fd12
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/Http.java
@@ -0,0 +1,31 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+public class Http {
+ public static final String HttpVers = "HTTP/1.0";
+
+ public static final String Vers1_0 = "HTTP/1.0";
+ public static final String Vers1_1 = "HTTP/1.1";
+ public static final String CRLF = "\r\n";
+
+ public static final char CR = '\r';
+ public static final char LF = '\n';
+ public static final char SP = ' ';
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpClient.java b/base/util/src/com/netscape/cmsutil/http/HttpClient.java
new file mode 100644
index 000000000..438c70c23
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpClient.java
@@ -0,0 +1,217 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+
+import com.netscape.cmsutil.net.ISocketFactory;
+
+/**
+ * basic http client.
+ * not optimized for performance.
+ * handles only string content.
+ */
+public class HttpClient {
+ protected ISocketFactory mFactory = null;
+
+ protected Socket mSocket = null;
+ protected InputStream mInputStream = null;
+ protected OutputStream mOutputStream = null;
+
+ protected InputStreamReader mInputStreamReader = null;
+ protected OutputStreamWriter mOutputStreamWriter = null;
+ protected BufferedReader mBufferedReader = null;
+ protected SSLCertificateApprovalCallback mCertApprovalCallback = null;
+ protected boolean mConnected = false;
+
+ public HttpClient() {
+ }
+
+ public HttpClient(ISocketFactory factory) {
+ mFactory = factory;
+ }
+
+ public HttpClient(ISocketFactory factory, SSLCertificateApprovalCallback certApprovalCallback) {
+ mFactory = factory;
+ mCertApprovalCallback = certApprovalCallback;
+ }
+
+ public void connect(String host, int port)
+ throws IOException {
+ if (mFactory != null) {
+ if (mCertApprovalCallback == null) {
+ mSocket = mFactory.makeSocket(host, port);
+ } else {
+ mSocket = mFactory.makeSocket(host, port, mCertApprovalCallback, null);
+ }
+ } else {
+ mSocket = new Socket(host, port);
+ }
+
+ if (mSocket == null) {
+ IOException e = new IOException("Couldn't make connection");
+
+ throw e;
+ }
+
+ mInputStream = mSocket.getInputStream();
+ mOutputStream = mSocket.getOutputStream();
+ mInputStreamReader = new InputStreamReader(mInputStream, "UTF8");
+ mBufferedReader = new BufferedReader(mInputStreamReader);
+ mOutputStreamWriter = new OutputStreamWriter(mOutputStream, "UTF8");
+ mConnected = true;
+ }
+
+ // Inserted by beomsuk
+ public void connect(String host, int port, int timeout)
+ throws IOException {
+ if (mFactory != null) {
+ mSocket = mFactory.makeSocket(host, port, timeout);
+ } else {
+ mSocket = new Socket(host, port);
+ }
+
+ if (mSocket == null) {
+ IOException e = new IOException("Couldn't make connection");
+
+ throw e;
+ }
+
+ mInputStream = mSocket.getInputStream();
+ mOutputStream = mSocket.getOutputStream();
+ mInputStreamReader = new InputStreamReader(mInputStream, "UTF8");
+ mBufferedReader = new BufferedReader(mInputStreamReader);
+ mOutputStreamWriter = new OutputStreamWriter(mOutputStream, "UTF8");
+ mConnected = true;
+ }
+
+ // Insert end
+ public boolean connected() {
+ return mConnected;
+ }
+
+ /**
+ * Sends a request to http server.
+ * Returns a http response.
+ */
+ public HttpResponse send(HttpRequest request)
+ throws IOException {
+ HttpResponse resp = new HttpResponse();
+
+ if (mOutputStream == null)
+ throw new IOException("Output stream not initialized");
+ request.write(mOutputStreamWriter);
+ try {
+ resp.parse(mBufferedReader);
+ } catch (IOException e) {
+ // XXX should we disconnect in all cases ?
+ disconnect();
+ throw e;
+ }
+ disconnect();
+ return resp;
+ }
+
+ public void disconnect()
+ throws IOException {
+ mSocket.close();
+ mInputStream = null;
+ mOutputStream = null;
+ mConnected = false;
+ }
+
+ public InputStream getInputStream() {
+ return mInputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return mOutputStream;
+ }
+
+ public BufferedReader getBufferedReader() {
+ return mBufferedReader;
+ }
+
+ public InputStreamReader getInputStreamReader() {
+ return mInputStreamReader;
+ }
+
+ public OutputStreamWriter getOutputStreamWriter() {
+ return mOutputStreamWriter;
+ }
+
+ public Socket getSocket() {
+ return mSocket;
+ }
+
+ /**
+ * unit test
+ */
+ public static void main(String args[])
+ throws Exception {
+ HttpClient c = new HttpClient();
+ HttpRequest req = new HttpRequest();
+ HttpResponse resp = null;
+
+ System.out.println("connecting to " + args[0] + " " + args[1]);
+ c.connect(args[0], Integer.parseInt(args[1]));
+
+ req.setMethod("GET");
+ req.setURI(args[2]);
+ if (args.length >= 4)
+ req.setHeader("Connection", args[3]);
+ resp = c.send(req);
+
+ System.out.println("version " + resp.getHttpVers());
+ System.out.println("status code " + resp.getStatusCode());
+ System.out.println("reason " + resp.getReasonPhrase());
+ System.out.println("content " + resp.getContent());
+
+ //String lenstr = resp.getHeader("Content-Length");
+ //System.out.println("content len is "+lenstr);
+ //int length = Integer.parseInt(lenstr);
+ //char[] content = new char[length];
+ //c.mBufferedReader.read(content, 0, content.length);
+ //System.out.println(content);
+
+ if (args.length >= 4 && args[3].equalsIgnoreCase("keep-alive")) {
+ for (int i = 0; i < 2; i++) {
+ if (i == 1)
+ req.setHeader("Connection", "Close");
+ resp = c.send(req);
+ System.out.println("version " + resp.getHttpVers());
+ System.out.println("status code " + resp.getStatusCode());
+ System.out.println("reason " + resp.getReasonPhrase());
+ System.out.println("content " + resp.getContent());
+ //len = Integer.parseInt(resp.getHeader("Content-Length"));
+ //System.out.println("content len is "+len);
+ //msgbody = new char[len];
+ //c.mBufferedReader.read(msgbody, 0, len);
+ //System.out.println(content);
+ }
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpEofException.java b/base/util/src/com/netscape/cmsutil/http/HttpEofException.java
new file mode 100644
index 000000000..824b9ea2a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpEofException.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.IOException;
+
+public class HttpEofException extends IOException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 433303354049669059L;
+
+ public HttpEofException() {
+ super();
+ }
+
+ public HttpEofException(String msg) {
+ super(msg);
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpMessage.java b/base/util/src/com/netscape/cmsutil/http/HttpMessage.java
new file mode 100644
index 000000000..badec5930
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpMessage.java
@@ -0,0 +1,163 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Basic HTTP Message, excluding message body.
+ * Not optimized for performance.
+ * Set fields or parse from input.
+ */
+public class HttpMessage {
+ protected String mLine = null; // request or response line.
+ protected Hashtable<String, String> mHeaders = null;
+ protected String mContent = null; // arbitrary content chars assumed.
+
+ /**
+ * Instantiate a HttpResponse for write to http client.
+ */
+ public HttpMessage() {
+ mHeaders = new Hashtable<String, String>();
+ }
+
+ /**
+ * Set a header field. <br>
+ * Content-length is automatically set on write.<br>
+ * If value spans multiple lines must be in proper http format for
+ * multiple lines.
+ */
+ public void setHeader(String name, String value) {
+ if (mHeaders == null)
+ mHeaders = new Hashtable<String, String>();
+ mHeaders.put(name.toLowerCase(), value);
+ }
+
+ /**
+ * get a header
+ */
+ public String getHeader(String name) {
+ return (String) mHeaders.get(name.toLowerCase());
+ }
+
+ /**
+ * write http headers
+ * does not support values of more than one line
+ */
+ public void writeHeaders(OutputStreamWriter writer)
+ throws IOException {
+ if (mHeaders != null) {
+ Enumeration<String> keys = mHeaders.keys();
+ String header, value;
+
+ while (keys.hasMoreElements()) {
+ header = keys.nextElement();
+ value = mHeaders.get(header);
+ writer.write(header + ":" + value + Http.CRLF);
+ }
+ }
+ writer.write(Http.CRLF); // end with CRLF line.
+ }
+
+ /**
+ * read http headers.
+ * does not support values of more than one line or multivalue headers.
+ */
+ public void readHeaders(BufferedReader reader)
+ throws IOException {
+ mHeaders = new Hashtable<String, String>();
+
+ int colon;
+ String line, key, value;
+
+ while (true) {
+ line = reader.readLine();
+ if (line == null || line.equals(""))
+ break;
+ colon = line.indexOf(':');
+ if (colon == -1) {
+ mHeaders = null;
+ throw new HttpProtocolException("Bad Http header format");
+ }
+ key = line.substring(0, colon);
+ value = line.substring(colon + 1);
+ mHeaders.put(key.toLowerCase(), value.trim());
+ }
+ }
+
+ public void write(OutputStreamWriter writer)
+ throws IOException {
+ writer.write(mLine + Http.CRLF);
+ writeHeaders(writer);
+ writer.flush();
+ if (mContent != null) {
+ writer.write(mContent);
+ }
+ writer.flush();
+ }
+
+ public void parse(BufferedReader reader)
+ throws IOException {
+ String line = reader.readLine();
+
+ // if (line == null) {
+ // throw new HttpEofException("End of stream reached");
+ // }
+ if (line.equals("")) {
+ throw new HttpProtocolException("Bad Http req/resp line " + line);
+ }
+ mLine = line;
+ readHeaders(reader);
+
+ // won't work if content length is not set.
+ String lenstr = mHeaders.get("content-length");
+
+ if (lenstr != null) {
+ int len = Integer.parseInt(lenstr);
+ char[] cbuf = new char[len];
+ int done = reader.read(cbuf, 0, cbuf.length);
+ int total = done;
+
+ while (done >= 0 && total < len) {
+ done = reader.read(cbuf, total, len - total);
+ total += done;
+ }
+
+ mContent = new String(cbuf);
+ }
+ }
+
+ public void reset() {
+ mLine = null;
+ mHeaders = null;
+ mContent = null;
+ }
+
+ public void setContent(String content) {
+ mContent = content;
+ }
+
+ public String getContent() {
+ return mContent;
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java b/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java
new file mode 100644
index 000000000..b5ceb1d7f
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.IOException;
+
+public class HttpProtocolException extends IOException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -953002842302351684L;
+
+ public HttpProtocolException() {
+ super();
+ }
+
+ public HttpProtocolException(String msg) {
+ super(msg);
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpRequest.java b/base/util/src/com/netscape/cmsutil/http/HttpRequest.java
new file mode 100644
index 000000000..9024dabf0
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpRequest.java
@@ -0,0 +1,137 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+/**
+ * Basic HTTP Request. not optimized for performance.
+ * Set fields or parse from input.
+ * Handles text content.
+ */
+public class HttpRequest extends HttpMessage {
+ public static final String GET = "GET";
+ public static final String POST = "POST";
+ public static final String HEAD = "HEAD";
+
+ protected String mMethod = null;
+ protected String mURI = null;
+ protected String mHttpVers = null;
+
+ /**
+ * Instantiate a HttpResponse for write to http client.
+ */
+ public HttpRequest() {
+ super();
+ }
+
+ /**
+ * set set request method.
+ */
+ public void setMethod(String method)
+ throws HttpProtocolException {
+ if (!method.equals(GET) && !method.equals(HEAD) &&
+ !method.equals(POST))
+ throw new HttpProtocolException("No such method " + method);
+ mMethod = method;
+ }
+
+ /**
+ * set reason phrase.
+ */
+ public void setURI(String uri) {
+ mURI = uri;
+ }
+
+ /**
+ * write request to the http client
+ */
+ public void write(OutputStreamWriter writer)
+ throws IOException {
+ if (mMethod == null || mURI == null) {
+ HttpProtocolException e = new HttpProtocolException(
+ "Http request method or uri not initialized");
+
+ //e.printStackTrace();
+ throw e;
+ }
+
+ mLine = mMethod + " " + mURI + " " + Http.HttpVers;
+ super.write(writer);
+ }
+
+ /**
+ * parse a http request from a http client
+ */
+ public void parse(BufferedReader reader)
+ throws IOException {
+ super.parse(reader);
+
+ int method = mLine.indexOf(Http.SP);
+
+ mMethod = mLine.substring(0, method);
+ if (!mMethod.equals(GET) && !mMethod.equals(POST) &&
+ !mMethod.equals(HEAD)) {
+ reset();
+ throw new HttpProtocolException("Bad Http request method");
+ }
+
+ int uri = mLine.lastIndexOf(Http.SP);
+
+ mURI = mLine.substring(method + 1, uri);
+
+ mHttpVers = mLine.substring(uri + 1);
+ if (!mHttpVers.equals("")) {
+ if (!mHttpVers.equals(Http.Vers1_0) &&
+ !mHttpVers.equals(Http.Vers1_1)) {
+ reset();
+ throw new HttpProtocolException("Bad Http version in request");
+ }
+ }
+ }
+
+ public void reset() {
+ mMethod = null;
+ mURI = null;
+ mHttpVers = null;
+ super.reset();
+ }
+
+ /**
+ * get method
+ */
+ public String getMethod() {
+ return mMethod;
+ }
+
+ /**
+ * get reason phrase
+ */
+ public String getURI() {
+ return mURI;
+ }
+
+ /**
+ * get http version
+ */
+ public String getHttpVers() {
+ return mHttpVers;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/HttpResponse.java b/base/util/src/com/netscape/cmsutil/http/HttpResponse.java
new file mode 100644
index 000000000..7ac7e2f69
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/HttpResponse.java
@@ -0,0 +1,139 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+/**
+ * Basic HTTP Response.
+ * Set fields or parse from input.
+ * Handles only text content.
+ */
+public class HttpResponse extends HttpMessage {
+ protected String mStatusCode = null;
+ protected String mReasonPhrase = null;
+ protected String mHttpVers = null;
+
+ /**
+ * Instantiate a HttpResponse for write to http client.
+ */
+ public HttpResponse() {
+ super();
+ }
+
+ /**
+ * set status code of response
+ */
+ public void setStatusCode(int code) {
+ mStatusCode = String.valueOf(code);
+ }
+
+ /**
+ * set reason phrase.
+ */
+ public void setReasonPhrase(String phrase) {
+ mReasonPhrase = phrase;
+ }
+
+ /**
+ * get status code
+ */
+ public String getStatusCode() {
+ return mStatusCode;
+ }
+
+ /**
+ * get reason phrase
+ */
+ public String getReasonPhrase() {
+ return mReasonPhrase;
+ }
+
+ /**
+ * write the response out to the http client
+ */
+ public void write(OutputStreamWriter writer)
+ throws IOException {
+ if (mStatusCode == null) {
+ throw new HttpProtocolException("status code not set in response");
+ }
+ // write status-line
+ mLine = Http.HttpVers + " " + mStatusCode + " ";
+ if (mReasonPhrase != null)
+ mLine += mReasonPhrase;
+ mLine += Http.CRLF;
+ super.write(writer);
+ }
+
+ /**
+ * parse a http response from a http server
+ */
+ public void parse(BufferedReader reader)
+ throws IOException {
+ mHttpVers = null;
+ mStatusCode = null;
+ mReasonPhrase = null;
+
+ super.parse(reader);
+
+ int httpvers = mLine.indexOf(' ');
+
+ if (httpvers == -1) {
+ reset();
+ throw new HttpProtocolException("no Http version in response");
+ }
+ mHttpVers = mLine.substring(0, httpvers);
+ if (!mHttpVers.equals(Http.Vers1_0) &&
+ !mHttpVers.equals(Http.Vers1_1)) {
+ reset();
+ throw new HttpProtocolException("Bad Http version in response");
+ }
+
+ int code = mLine.indexOf(' ', httpvers + 1);
+
+ if (code == -1) {
+ reset();
+ throw new HttpProtocolException("no status code in response");
+ }
+ mStatusCode = mLine.substring(httpvers + 1, code);
+ try {
+ Integer.parseInt(mStatusCode);
+ } catch (NumberFormatException e) {
+ reset();
+ throw new HttpProtocolException("Bad status code in response");
+ }
+
+ mReasonPhrase = mLine.substring(code + 1);
+ }
+
+ public void reset() {
+ mStatusCode = null;
+ mHttpVers = null;
+ mReasonPhrase = null;
+ super.reset();
+ }
+
+ /**
+ * get http version
+ */
+ public String getHttpVers() {
+ return mHttpVers;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
new file mode 100644
index 000000000..c2013a5d2
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
@@ -0,0 +1,182 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.http;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
+import org.mozilla.jss.ssl.SSLSocket;
+
+import com.netscape.cmsutil.net.ISocketFactory;
+
+/**
+ * Uses NSS ssl socket.
+ *
+ * @version $Revision$ $Date$
+ */
+public class JssSSLSocketFactory implements ISocketFactory {
+ private String mClientAuthCertNickname = null;
+ private SSLSocket s = null;
+
+ public JssSSLSocketFactory() {
+ }
+
+ public JssSSLSocketFactory(String certNickname) {
+ mClientAuthCertNickname = certNickname;
+ }
+
+ // XXX remove these static SSL cipher suite initializations later on.
+ static final int cipherSuites[] = {
+ SSLSocket.SSL3_RSA_WITH_RC4_128_MD5,
+ SSLSocket.SSL3_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSLSocket.SSL3_RSA_WITH_DES_CBC_SHA,
+ SSLSocket.SSL3_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSLSocket.SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ SSLSocket.SSL3_RSA_WITH_NULL_MD5,
+ SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ SSLSocket.TLS_RSA_WITH_AES_128_CBC_SHA,
+ SSLSocket.TLS_RSA_WITH_AES_256_CBC_SHA,
+ SSLSocket.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ SSLSocket.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ SSLSocket.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ SSLSocket.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ 0
+ };
+
+ static {
+ int i;
+
+ for (i = SSLSocket.SSL2_RC4_128_WITH_MD5; i <= SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5; ++i) {
+ try {
+ SSLSocket.setCipherPreferenceDefault(i, false);
+ } catch (SocketException e) {
+ }
+ }
+
+ //skip SSL_EN_IDEA_128_EDE3_CBC_WITH_MD5
+ for (i = SSLSocket.SSL2_DES_64_CBC_WITH_MD5; i <= SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5; ++i) {
+ try {
+ SSLSocket.setCipherPreferenceDefault(i, false);
+ } catch (SocketException e) {
+ }
+ }
+ for (i = 0; cipherSuites[i] != 0; ++i) {
+ try {
+ SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true);
+ } catch (SocketException e) {
+ }
+ }
+ }
+
+ public Socket makeSocket(String host, int port)
+ throws IOException, UnknownHostException {
+ return makeSocket(host, port, null, null);
+ }
+
+ public Socket makeSocket(String host, int port,
+ SSLCertificateApprovalCallback certApprovalCallback,
+ SSLClientCertificateSelectionCallback clientCertCallback)
+ throws IOException, UnknownHostException {
+
+ try {
+ s = new SSLSocket(host, port, null, 0, certApprovalCallback,
+ clientCertCallback);
+ for (int i = 0; cipherSuites[i] != 0; ++i) {
+ try {
+ SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true);
+ } catch (SocketException e) {
+ }
+ }
+
+ s.setUseClientMode(true);
+ s.enableSSL2(false);
+ //TODO Do we rally want to set the default each time?
+ SSLSocket.enableSSL2Default(false);
+ s.enableV2CompatibleHello(false);
+
+ SSLHandshakeCompletedListener listener = null;
+
+ listener = new ClientHandshakeCB(this);
+ s.addHandshakeCompletedListener(listener);
+
+ if (mClientAuthCertNickname != null) {
+ // 052799 setClientCertNickname does not
+ // report error if the nickName is invalid.
+ // So we check this ourself using
+ // findCertByNickname
+ CryptoManager.getInstance().findCertByNickname(mClientAuthCertNickname);
+
+ s.setClientCertNickname(mClientAuthCertNickname);
+ }
+ s.forceHandshake();
+ } catch (org.mozilla.jss.crypto.ObjectNotFoundException e) {
+ throw new IOException(e.toString());
+ } catch (org.mozilla.jss.crypto.TokenException e) {
+ throw new IOException(e.toString());
+ } catch (UnknownHostException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ return s;
+ }
+
+ public Socket makeSocket(String host, int port, int timeout)
+ throws IOException, UnknownHostException {
+ Thread t = new ConnectAsync(this, host, port);
+
+ t.start();
+ try {
+ t.join(1000 * timeout);
+ } catch (InterruptedException e) {
+ }
+
+ if (t.isAlive()) {
+ }
+
+ return s;
+ }
+
+ public void log(int level, String msg) {
+ }
+
+ class ClientHandshakeCB implements SSLHandshakeCompletedListener {
+ Object sc;
+
+ public ClientHandshakeCB(Object sc) {
+ this.sc = sc;
+ }
+
+ public void handshakeCompleted(SSLHandshakeCompletedEvent event) {
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java
new file mode 100644
index 000000000..e821db67a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java
@@ -0,0 +1,101 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ldap;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPAttributeSet;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+import netscape.ldap.util.LDIF;
+import netscape.ldap.util.LDIFAttributeContent;
+import netscape.ldap.util.LDIFContent;
+import netscape.ldap.util.LDIFModifyContent;
+import netscape.ldap.util.LDIFRecord;
+
+public class LDAPUtil {
+
+ // special chars are *, (, ), \, null
+ public static String SPECIAL_CHARS = "*()\\\000";
+
+ /**
+ * This method escapes special characters for LDAP filter (RFC 4515).
+ * Each special character will be replaced by a backslash followed by
+ * 2-digit hex of the ASCII code.
+ *
+ * @param string string to escape
+ * @return escaped string
+ */
+ public static String escape(String string) {
+ StringBuilder sb = new StringBuilder();
+ for (char c : string.toCharArray()) {
+ if (SPECIAL_CHARS.indexOf(c) >= 0) {
+ sb.append('\\');
+ if (c < 0x10) sb.append('0'); // make sure it's 2-digit
+ sb.append(Integer.toHexString(c));
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static void importLDIF(LDAPConnection conn, String filename, ArrayList<String> errors) throws IOException {
+ LDIF ldif = new LDIF(filename);
+ while (true) {
+ try {
+ LDIFRecord record = ldif.nextRecord();
+ if (record == null)
+ break;
+
+ String dn = record.getDN();
+ LDIFContent content = record.getContent();
+ int type = content.getType();
+ if (type == LDIFContent.ATTRIBUTE_CONTENT) {
+ LDIFAttributeContent c = (LDIFAttributeContent) content;
+ LDAPAttribute[] attrs = c.getAttributes();
+ LDAPAttributeSet myAttrs = new LDAPAttributeSet();
+ for (int i = 0; i < attrs.length; i++)
+ myAttrs.add(attrs[i]);
+ LDAPEntry entry = new LDAPEntry(dn, myAttrs);
+ try {
+ conn.add(entry);
+ } catch (LDAPException ee) {
+ errors.add("LDAPUtil:importLDIF: exception in adding entry " + dn +
+ ":" + ee.toString() + "\n");
+ }
+ } else if (type == LDIFContent.MODIFICATION_CONTENT) {
+ LDIFModifyContent c = (LDIFModifyContent) content;
+ LDAPModification[] mods = c.getModifications();
+ try {
+ conn.modify(dn, mods);
+ } catch (LDAPException ee) {
+ errors.add("LDAPUtil:importLDIF: exception in modifying entry " + dn +
+ ":" + ee.toString());
+ }
+ }
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/net/ISocketFactory.java b/base/util/src/com/netscape/cmsutil/net/ISocketFactory.java
new file mode 100644
index 000000000..18f6cac88
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/net/ISocketFactory.java
@@ -0,0 +1,38 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.net;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
+
+public interface ISocketFactory {
+ Socket makeSocket(String host, int port)
+ throws IOException, UnknownHostException;
+
+ Socket makeSocket(String host, int port, int timeout)
+ throws IOException, UnknownHostException;
+
+ Socket makeSocket(String host, int port,
+ SSLCertificateApprovalCallback certApprovalCallback,
+ SSLClientCertificateSelectionCallback clientCertCallback)
+ throws IOException, UnknownHostException;
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/BasicOCSPResponse.java b/base/util/src/com/netscape/cmsutil/ocsp/BasicOCSPResponse.java
new file mode 100644
index 000000000..11ae7f152
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/BasicOCSPResponse.java
@@ -0,0 +1,195 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Certificate;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class BasicOCSPResponse implements Response {
+ private byte mData[] = null;
+ private ResponseData _rd = null;
+ private AlgorithmIdentifier _signAlg = null;
+ private BIT_STRING _signature = null;
+ private Certificate _certs[] = null;
+
+ public BasicOCSPResponse(ResponseData rd, AlgorithmIdentifier signAlg,
+ BIT_STRING signature, Certificate certs[]) {
+ _rd = rd;
+ _signAlg = signAlg;
+ _signature = signature;
+ _certs = certs;
+ }
+
+ public BasicOCSPResponse(OCTET_STRING os) {
+ this(os.toByteArray());
+ }
+
+ public BasicOCSPResponse(byte data[]) {
+ mData = data;
+
+ // extract _rd, _signAlg, _signature and _certs
+ try {
+ BasicOCSPResponse resp = (BasicOCSPResponse) getTemplate().decode(new ByteArrayInputStream(data));
+ _rd = resp.getResponseData();
+ _signAlg = resp.getSignatureAlgorithm();
+ _signature = resp.getSignature();
+ _certs = resp.getCerts();
+ } catch (Exception e) {
+ // exception in decoding byte data
+ }
+ }
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ if (mData != null) {
+ os.write(mData);
+ } else {
+ SEQUENCE seq = new SEQUENCE();
+ seq.addElement(_rd);
+ seq.addElement(_signAlg);
+ seq.addElement(_signature);
+ if (_certs != null) {
+ SEQUENCE certsSeq = new SEQUENCE();
+ for (Certificate c : _certs) {
+ certsSeq.addElement(c);
+ }
+ EXPLICIT certsExplicit = new EXPLICIT(new Tag(0), certsSeq);
+ seq.addElement(certsExplicit);
+ }
+ seq.encode(t, os);
+ }
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(TAG, os);
+ }
+
+ public OCTET_STRING getBytes() {
+ return null;
+ }
+
+ public ResponseData getResponseData() {
+ return _rd;
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm() {
+ return _signAlg;
+ }
+
+ public BIT_STRING getSignature() {
+ return _signature;
+ }
+
+ public int getCertsCount() {
+ return (_certs != null) ? _certs.length : 0;
+ }
+
+ public Certificate[] getCerts() {
+ return _certs;
+ }
+
+ public Certificate getCertificateAt(int pos) {
+ return (_certs != null) ? _certs[pos] : null;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(ResponseData.getTemplate());
+ seqt.addElement(AlgorithmIdentifier.getTemplate());
+ seqt.addElement(BIT_STRING.getTemplate());
+ seqt.addOptionalElement(new EXPLICIT.Template(
+ new Tag(0), new SEQUENCE.OF_Template(
+ Certificate.getTemplate())));
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ ResponseData rd = (ResponseData) seq.elementAt(0);
+ AlgorithmIdentifier alg = (AlgorithmIdentifier) seq.elementAt(1);
+ BIT_STRING bs = (BIT_STRING) seq.elementAt(2);
+ Certificate[] certs = null;
+ if (seq.size() == 4) {
+ // optional certificates are present
+ EXPLICIT certSeqExplicit = (EXPLICIT) seq.elementAt(3);
+ SEQUENCE certSeq = (SEQUENCE) certSeqExplicit.getContent();
+ if (certSeq != null) {
+ certs = new Certificate[certSeq.size()];
+ for (int x = 0; x < certSeq.size(); x++) {
+ certs[x] = (Certificate) certSeq.elementAt(x);
+ }
+ }
+ }
+
+ return new BasicOCSPResponse(rd, alg, bs, certs);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/CertID.java b/base/util/src/com/netscape/cmsutil/ocsp/CertID.java
new file mode 100644
index 000000000..b6979c784
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/CertID.java
@@ -0,0 +1,155 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class CertID implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private AlgorithmIdentifier hashAlgorithm;
+ private OCTET_STRING issuerNameHash;
+ private OCTET_STRING issuerKeyHash;
+ private INTEGER serialNumber;
+ private SEQUENCE sequence;
+
+ public AlgorithmIdentifier getHashAlgorithm() {
+ return hashAlgorithm;
+ }
+
+ public OCTET_STRING getIssuerNameHash() {
+ return issuerNameHash;
+ }
+
+ public OCTET_STRING getIssuerKeyHash() {
+ return issuerKeyHash;
+ }
+
+ public INTEGER getSerialNumber() {
+ return serialNumber;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Constructors
+ ///////////////////////////////////////////////////////////////////////
+
+ public CertID(AlgorithmIdentifier hashAlgorithm,
+ OCTET_STRING issuerNameHash, OCTET_STRING issuerKeyHash,
+ INTEGER serialNumber) {
+ sequence = new SEQUENCE();
+
+ this.hashAlgorithm = hashAlgorithm;
+ sequence.addElement(hashAlgorithm);
+
+ this.issuerNameHash = issuerNameHash;
+ sequence.addElement(issuerNameHash);
+
+ this.issuerKeyHash = issuerKeyHash;
+ sequence.addElement(issuerKeyHash);
+
+ this.serialNumber = serialNumber;
+ sequence.addElement(serialNumber);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encoding/decoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding a <code>CertID</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(AlgorithmIdentifier.getTemplate());
+ seqt.addElement(OCTET_STRING.getTemplate());
+ seqt.addElement(OCTET_STRING.getTemplate());
+ seqt.addElement(INTEGER.getTemplate());
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ return new CertID(
+ (AlgorithmIdentifier) seq.elementAt(0),
+ (OCTET_STRING) seq.elementAt(1),
+ (OCTET_STRING) seq.elementAt(2),
+ (INTEGER) seq.elementAt(3));
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/CertStatus.java b/base/util/src/com/netscape/cmsutil/ocsp/CertStatus.java
new file mode 100644
index 000000000..a90eb215f
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/CertStatus.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import org.mozilla.jss.asn1.ASN1Value;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public interface CertStatus extends ASN1Value {
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/GoodInfo.java b/base/util/src/com/netscape/cmsutil/ocsp/GoodInfo.java
new file mode 100644
index 000000000..fa7387260
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/GoodInfo.java
@@ -0,0 +1,98 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.NULL;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class GoodInfo implements CertStatus {
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public GoodInfo() {
+ }
+
+ public Tag getTag() {
+ return Tag.get(0);
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ NULL.getInstance().encode(getTag(), os);
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(getTag(), os);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(new NULL.Template());
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ // SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ // istream);
+
+ return new GoodInfo();
+
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/KeyHashID.java b/base/util/src/com/netscape/cmsutil/ocsp/KeyHashID.java
new file mode 100644
index 000000000..358fb0ebd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/KeyHashID.java
@@ -0,0 +1,105 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * ResponderID ::= CHOICE {
+ * byName [1] EXPLICIT Name,
+ * byKey [2] EXPLICIT KeyHash }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class KeyHashID implements ResponderID {
+ private OCTET_STRING _hash = null;
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public KeyHashID(OCTET_STRING hash) {
+ _hash = hash;
+ }
+
+ public Tag getTag() {
+ return Tag.get(2);
+ }
+
+ public void encode(Tag tag, OutputStream os) throws IOException {
+ _hash.encode(os);
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ _hash.encode(os);
+ }
+
+ public OCTET_STRING getHash() {
+ return _hash;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ // seqt.addElement(new EXPLICIT.Template(
+ // new Tag (2), new OCTET_STRING.Template()) );
+ seqt.addElement(new OCTET_STRING.Template());
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ istream);
+
+ OCTET_STRING o = (OCTET_STRING) seq.elementAt(0);
+ return new KeyHashID(o);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/NameID.java b/base/util/src/com/netscape/cmsutil/ocsp/NameID.java
new file mode 100644
index 000000000..529ededbb
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/NameID.java
@@ -0,0 +1,106 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.primitive.Name;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * ResponderID ::= CHOICE {
+ * byName [1] EXPLICIT Name,
+ * byKey [2] EXPLICIT KeyHash }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class NameID implements ResponderID {
+ private Name _name = null;
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public NameID(Name n) {
+ _name = n;
+ }
+
+ public Tag getTag() {
+ return Tag.get(1);
+ }
+
+ public void encode(Tag tag, OutputStream os) throws IOException {
+ _name.encode(os);
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ _name.encode(os);
+ }
+
+ public Name getName() {
+ return _name;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ // seqt.addElement(new EXPLICIT.Template(
+ // new Tag (1), new Name.Template()) );
+ seqt.addElement(new Name.Template());
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ istream);
+
+ // EXPLICIT e_name = (EXPLICIT) seq.elementAt(0);
+ Name name = (Name) seq.elementAt(0);
+ return new NameID(name);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/OCSPRequest.java b/base/util/src/com/netscape/cmsutil/ocsp/OCSPRequest.java
new file mode 100644
index 000000000..963bdc832
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/OCSPRequest.java
@@ -0,0 +1,140 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * OCSPRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class OCSPRequest implements ASN1Value {
+
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private TBSRequest tbsRequest;
+ private Signature optionalSignature;
+ private SEQUENCE sequence;
+
+ /**
+ * Returns the <code>TBSRequest</code> field.
+ */
+ public TBSRequest getTBSRequest() {
+ return tbsRequest;
+ }
+
+ /**
+ * Returns the <code>Signature</code> field.
+ */
+ public Signature getSignature() {
+ return optionalSignature;
+ }
+
+ /* THIS code is probably broken. It does not properly encode the explicit element */
+
+ public OCSPRequest(TBSRequest tbsRequest, Signature optionalSignature) {
+ sequence = new SEQUENCE();
+
+ this.tbsRequest = tbsRequest;
+ sequence.addElement(tbsRequest);
+
+ this.optionalSignature = optionalSignature;
+ if (optionalSignature != null) {
+ sequence.addElement(optionalSignature);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encoding/decoding
+ ///////////////////////////////////////////////////////////////////////
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding OCSPRequest.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(TBSRequest.getTemplate());
+ seqt.addOptionalElement(new EXPLICIT.Template(new Tag(0),
+ new Signature.Template()));
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(istream);
+ Signature signature = null;
+ if (seq.elementAt(1) != null) {
+ signature = (Signature) ((EXPLICIT) seq.elementAt(1)).getContent();
+ }
+
+ return new OCSPRequest(
+ (TBSRequest) seq.elementAt(0),
+ signature);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponse.java b/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponse.java
new file mode 100644
index 000000000..6696cd9dc
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponse.java
@@ -0,0 +1,135 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class OCSPResponse implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private OCSPResponseStatus responseStatus = null;
+ private ResponseBytes responseBytes = null;
+ private SEQUENCE sequence;
+
+ public OCSPResponseStatus getResponseStatus() {
+ return responseStatus;
+ }
+
+ public ResponseBytes getResponseBytes() {
+ return responseBytes;
+ }
+
+ public OCSPResponse(OCSPResponseStatus responseStatus,
+ ResponseBytes responseBytes) {
+ sequence = new SEQUENCE();
+
+ this.responseStatus = responseStatus;
+ sequence.addElement(responseStatus);
+
+ this.responseBytes = responseBytes;
+ sequence.addElement(new EXPLICIT(Tag.get(0), responseBytes));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encoding/decoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding an <code>OCSPResponse</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(OCSPResponseStatus.getTemplate());
+ seqt.addOptionalElement(
+ new EXPLICIT.Template(
+ new Tag(0), new ResponseBytes.Template()));
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ OCSPResponseStatus rs = (OCSPResponseStatus) seq.elementAt(0);
+ ResponseBytes rb = null;
+ ASN1Value val = seq.elementAt(1);
+ if (val instanceof EXPLICIT) {
+ EXPLICIT exp = (EXPLICIT) val;
+ rb = (ResponseBytes) exp.getContent();
+ } else {
+ rb = (ResponseBytes) val;
+ }
+ return new OCSPResponse(rs, rb);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponseStatus.java b/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponseStatus.java
new file mode 100644
index 000000000..38ca881c2
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/OCSPResponseStatus.java
@@ -0,0 +1,120 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.ENUMERATED;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * OCSPResponseStatus ::= ENUMERATED {
+ * successful (0), --Response has valid confirmations
+ * malformedRequest (1), --Illegal confirmation request
+ * internalError (2), --Internal error in issuer
+ * tryLater (3), --Try again later
+ * --(4) is not used
+ * sigRequired (5), --Must sign the request
+ * unauthorized (6) --Request unauthorized
+ * }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class OCSPResponseStatus implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ public final static OCSPResponseStatus SUCCESSFUL =
+ new OCSPResponseStatus(0);
+ public final static OCSPResponseStatus MALFORMED_REQUEST =
+ new OCSPResponseStatus(1);
+ public final static OCSPResponseStatus INTERNAL_ERROR =
+ new OCSPResponseStatus(2);
+ public final static OCSPResponseStatus TRY_LATER =
+ new OCSPResponseStatus(3);
+ public final static OCSPResponseStatus SIG_REQUIRED =
+ new OCSPResponseStatus(5);
+ public final static OCSPResponseStatus UNAUTHORIZED =
+ new OCSPResponseStatus(6);
+
+ private ENUMERATED responseStatus;
+
+ public long getValue() {
+ return responseStatus.getValue();
+ }
+
+ public OCSPResponseStatus(long val) {
+ responseStatus = new ENUMERATED(val);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encoding/decoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = ENUMERATED.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ responseStatus.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding an <code>OCSPResponseStatus</code>.
+ */
+ public static class Template implements ASN1Template {
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ ENUMERATED.Template enumt = new ENUMERATED.Template();
+ ENUMERATED enum1 = (ENUMERATED) enumt.decode(implicitTag, istream);
+
+ return new OCSPResponseStatus(enum1.getValue());
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/Request.java b/base/util/src/com/netscape/cmsutil/ocsp/Request.java
new file mode 100644
index 000000000..85c97de22
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/Request.java
@@ -0,0 +1,147 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Extension;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class Request implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private CertID reqCert = null;
+ private SEQUENCE singleRequestExtensions = null;
+ private SEQUENCE sequence = null;
+
+ public CertID getCertID() {
+ return reqCert;
+ }
+
+ public int getExtensionsCount() {
+ if (singleRequestExtensions == null) {
+ return 0;
+ } else {
+ return singleRequestExtensions.size();
+ }
+ }
+
+ public Extension getRequestExtensionAt(int index) {
+ if (singleRequestExtensions == null) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return (Extension) singleRequestExtensions.elementAt(index);
+ }
+
+ public Request(CertID reqCert, SEQUENCE singleRequestExtensions) {
+ sequence = new SEQUENCE();
+
+ this.reqCert = reqCert;
+ sequence.addElement(reqCert);
+
+ if (singleRequestExtensions != null) {
+ this.singleRequestExtensions = singleRequestExtensions;
+ sequence.addElement(singleRequestExtensions);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encode / decode
+ ///////////////////////////////////////////////////////////////////////
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding Request.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(CertID.getTemplate());
+ seqt.addOptionalElement(new EXPLICIT.Template(new Tag(0),
+ new SEQUENCE.OF_Template(new Extension.Template())));
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ EXPLICIT tag = (EXPLICIT) seq.elementAt(1);
+
+ if (tag == null) {
+ return new Request(
+ (CertID) seq.elementAt(0),
+ (SEQUENCE) null);
+ } else {
+ return new Request(
+ (CertID) seq.elementAt(0),
+ (SEQUENCE) tag.getContent());
+ }
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/ResponderID.java b/base/util/src/com/netscape/cmsutil/ocsp/ResponderID.java
new file mode 100644
index 000000000..02e30de05
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/ResponderID.java
@@ -0,0 +1,34 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import org.mozilla.jss.asn1.ASN1Value;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * ResponderID ::= CHOICE {
+ * byName [1] EXPLICIT Name,
+ * byKey [2] EXPLICIT KeyHash }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public interface ResponderID extends ASN1Value {
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/Response.java b/base/util/src/com/netscape/cmsutil/ocsp/Response.java
new file mode 100644
index 000000000..0d363e811
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/Response.java
@@ -0,0 +1,34 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.OCTET_STRING;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * response OCTET STRING
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public interface Response extends ASN1Value {
+ public OCTET_STRING getBytes();
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/ResponseBytes.java b/base/util/src/com/netscape/cmsutil/ocsp/ResponseBytes.java
new file mode 100644
index 000000000..c5d461148
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/ResponseBytes.java
@@ -0,0 +1,130 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class ResponseBytes implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ public final static OBJECT_IDENTIFIER OCSP =
+ new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.48.1");
+ public final static OBJECT_IDENTIFIER OCSP_BASIC =
+ new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.48.1.1");
+
+ private OBJECT_IDENTIFIER responseType = null;
+ private OCTET_STRING response = null;
+ private SEQUENCE sequence;
+
+ public OBJECT_IDENTIFIER getObjectIdentifier() {
+ return responseType;
+ }
+
+ public OCTET_STRING getResponse() {
+ return response;
+ }
+
+ public ResponseBytes(OBJECT_IDENTIFIER responseType, OCTET_STRING response) {
+ sequence = new SEQUENCE();
+
+ this.responseType = responseType;
+ sequence.addElement(responseType);
+
+ this.response = response;
+ sequence.addElement(response);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encoding/decoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(OBJECT_IDENTIFIER.getTemplate());
+ seqt.addElement(OCTET_STRING.getTemplate());
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ return new ResponseBytes(
+ (OBJECT_IDENTIFIER) seq.elementAt(0),
+ (OCTET_STRING) seq.elementAt(1));
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/ResponseData.java b/base/util/src/com/netscape/cmsutil/ocsp/ResponseData.java
new file mode 100644
index 000000000..1b28cf134
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/ResponseData.java
@@ -0,0 +1,222 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.GeneralizedTime;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Extension;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class ResponseData implements ASN1Value {
+ private static final INTEGER v1 = new INTEGER(0);
+ private INTEGER mVer;
+ private ResponderID mRID = null;
+ private GeneralizedTime mProduced = null;
+ private SingleResponse mSR[] = null;
+ private Extension mExts[] = null;
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public ResponseData(INTEGER ver, ResponderID rid, GeneralizedTime produced,
+ SingleResponse sr[], Extension exts[]) {
+ mVer = (ver != null) ? ver : v1;
+ mRID = rid;
+ mProduced = produced;
+ mSR = sr;
+ mExts = exts;
+ }
+
+ public ResponseData(ResponderID rid, GeneralizedTime produced,
+ SingleResponse sr[]) {
+ this(v1, rid, produced, sr, null);
+ }
+
+ public ResponseData(ResponderID rid, GeneralizedTime produced,
+ SingleResponse sr[], Extension exts[]) {
+ this(v1, rid, produced, sr, exts);
+ }
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(null, os);
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ SEQUENCE seq = new SEQUENCE();
+
+ if (mVer != v1) {
+ seq.addElement(new EXPLICIT(Tag.get(0), new INTEGER(mVer)));
+ }
+
+ seq.addElement(new EXPLICIT(mRID.getTag(), mRID));
+ seq.addElement(mProduced);
+ SEQUENCE responses = new SEQUENCE();
+ for (int i = 0; i < mSR.length; i++) {
+ responses.addElement(mSR[i]);
+ }
+ seq.addElement(responses);
+ if (mExts != null) {
+ SEQUENCE exts = new SEQUENCE();
+ for (int i = 0; i < mExts.length; i++) {
+ exts.addElement(mExts[i]);
+ }
+ seq.addElement(new EXPLICIT(Tag.get(1), exts));
+ }
+ if (t == null) {
+ seq.encode(os);
+ } else {
+ seq.encode(t, os);
+ }
+ }
+
+ public ResponderID getResponderID() {
+ return mRID;
+ }
+
+ public GeneralizedTime getProducedAt() {
+ return mProduced;
+ }
+
+ public int getResponseCount() {
+ return (mSR != null) ? mSR.length : 0;
+ }
+
+ public SingleResponse getResponseAt(int pos) {
+ return (mSR != null) ? mSR[pos] : null;
+ }
+
+ public int getResponseExtensionCount() {
+ return (mExts != null) ? mExts.length : 0;
+ }
+
+ public Extension getResponseExtensionAt(int pos) {
+ return (mExts != null) ? mExts[pos] : null;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addOptionalElement(new EXPLICIT.Template(
+ new Tag(0), new INTEGER.Template()));
+ seqt.addElement(new ANY.Template());
+ seqt.addElement(new GeneralizedTime.Template());
+ seqt.addElement(new SEQUENCE.OF_Template(
+ SingleResponse.getTemplate()));
+ seqt.addOptionalElement(new EXPLICIT.Template(
+ new Tag(1), new SEQUENCE.OF_Template(
+ Extension.getTemplate())));
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ istream);
+
+ INTEGER ver = v1;
+ EXPLICIT e_ver = (EXPLICIT) seq.elementAt(0);
+ if (e_ver != null && e_ver.getTag().getNum() == 0) {
+ ver = (INTEGER) e_ver.getContent();
+ }
+ ResponderID rid = null;
+ ANY e_rid = (ANY) seq.elementAt(1);
+ if (e_rid.getTag().getNum() == 1) {
+ // name id
+ rid = (NameID)
+ NameID.getTemplate().decode(e_rid.getTag(),
+ new ByteArrayInputStream(e_rid.getEncoded()));
+ } else if (e_rid.getTag().getNum() == 2) {
+ // key hash id
+ rid = (KeyHashID)
+ KeyHashID.getTemplate().decode(e_rid.getTag(),
+ new ByteArrayInputStream(e_rid.getEncoded()));
+ }
+ GeneralizedTime producedAt = (GeneralizedTime) seq.elementAt(2);
+ SEQUENCE responses = (SEQUENCE) seq.elementAt(3);
+ SingleResponse sr[] = null;
+ if ((responses != null) && (responses.size() > 0)) {
+ sr = new SingleResponse[responses.size()];
+ for (int i = 0; i < responses.size(); i++) {
+ sr[i] = (SingleResponse) responses.elementAt(i);
+ }
+ }
+
+ //decode response extension sequence
+ EXPLICIT extns_exp = (EXPLICIT) seq.elementAt(4);
+ SEQUENCE extns_seq;
+ Extension[] extns_array = null;
+ if (extns_exp != null) {
+ extns_seq = (SEQUENCE) extns_exp.getContent();
+ extns_array = new Extension[extns_seq.size()];
+ for (int x = 0; x < extns_array.length; x++) {
+ extns_array[x] = (Extension) extns_seq.elementAt(x);
+ }
+ }
+
+ return new ResponseData(ver, rid, producedAt, sr, extns_array);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/RevokedInfo.java b/base/util/src/com/netscape/cmsutil/ocsp/RevokedInfo.java
new file mode 100644
index 000000000..9b0b2d186
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/RevokedInfo.java
@@ -0,0 +1,113 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.GeneralizedTime;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class RevokedInfo implements CertStatus {
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ private GeneralizedTime mRevokedAt;
+
+ public RevokedInfo(GeneralizedTime revokedAt) {
+ mRevokedAt = revokedAt;
+ }
+
+ public Tag getTag() {
+ return Tag.get(1);
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ SEQUENCE seq = new SEQUENCE();
+ seq.addElement(mRevokedAt);
+ seq.encode(t, os);
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(getTag(), os);
+ }
+
+ public GeneralizedTime getRevocationTime() {
+ return mRevokedAt;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(new GeneralizedTime.Template());
+ seqt.addOptionalElement(
+ new EXPLICIT.Template(new Tag(0),
+ new INTEGER.Template()));
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ istream);
+
+ GeneralizedTime revokedAt = (GeneralizedTime)
+ seq.elementAt(0);
+ return new RevokedInfo(revokedAt);
+
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/Signature.java b/base/util/src/com/netscape/cmsutil/ocsp/Signature.java
new file mode 100644
index 000000000..b9b192aee
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/Signature.java
@@ -0,0 +1,159 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Certificate;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class Signature implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // Members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private AlgorithmIdentifier signatureAlgorithm;
+ private BIT_STRING signature;
+ private SEQUENCE certs;
+ private SEQUENCE sequence;
+
+ public AlgorithmIdentifier getSignatureAlgorithm() {
+ return signatureAlgorithm;
+ }
+
+ public BIT_STRING getSignature() {
+ return signature;
+ }
+
+ public int getCertificateCount() {
+ if (certs == null) {
+ return 0;
+ } else {
+ return certs.size();
+ }
+ }
+
+ public Certificate getCertificateAt(int index) {
+ if (certs == null) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return (Certificate) certs.elementAt(index);
+ }
+
+ public Signature(AlgorithmIdentifier signatureAlgorithm,
+ BIT_STRING signature, SEQUENCE certs) {
+ sequence = new SEQUENCE();
+
+ this.signatureAlgorithm = signatureAlgorithm;
+ sequence.addElement(signatureAlgorithm);
+
+ this.signature = signature;
+ sequence.addElement(signature);
+
+ this.certs = certs;
+ sequence.addElement(certs);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encode / decode
+ ///////////////////////////////////////////////////////////////////////
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ sequence.encode(implicitTag, ostream);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding Request.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(AlgorithmIdentifier.getTemplate());
+ seqt.addElement(BIT_STRING.getTemplate());
+ seqt.addOptionalElement(
+ new EXPLICIT.Template(
+ new Tag(0),
+ new SEQUENCE.OF_Template(new Certificate.Template())
+ )
+ );
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+ SEQUENCE certs = null;
+ if (seq.elementAt(2) != null) {
+ certs = (SEQUENCE) ((EXPLICIT) seq.elementAt(2)).getContent();
+ }
+
+ return new Signature(
+ (AlgorithmIdentifier) seq.elementAt(0),
+ (BIT_STRING) seq.elementAt(1),
+ certs);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/SingleResponse.java b/base/util/src/com/netscape/cmsutil/ocsp/SingleResponse.java
new file mode 100644
index 000000000..ab54e5019
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/SingleResponse.java
@@ -0,0 +1,182 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.GeneralizedTime;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Extension;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class SingleResponse implements ASN1Value {
+ private CertID mCID = null;
+ private CertStatus mStatus = null;
+ private GeneralizedTime mThisUpdate = null;
+ private GeneralizedTime mNextUpdate = null;
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public SingleResponse(CertID cid, CertStatus s,
+ GeneralizedTime thisUpdate, GeneralizedTime nextUpdate) {
+ mCID = cid;
+ mStatus = s;
+ mThisUpdate = thisUpdate;
+ mNextUpdate = nextUpdate;
+ }
+
+ public CertID getCertID() {
+ return mCID;
+ }
+
+ public Tag getTag() {
+ return null;
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ SEQUENCE seq = new SEQUENCE();
+ seq.addElement(mCID);
+ seq.addElement(mStatus);
+ seq.addElement(mThisUpdate);
+ if (mNextUpdate != null) {
+ seq.addElement(new EXPLICIT(Tag.get(0), mNextUpdate));
+ }
+ if (t == null) {
+ seq.encode(os);
+ } else {
+ seq.encode(t, os);
+ }
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(null, os);
+ }
+
+ public CertStatus getCertStatus() {
+ return mStatus;
+ }
+
+ public GeneralizedTime getThisUpdate() {
+ return mThisUpdate;
+ }
+
+ public GeneralizedTime getNextUpdate() {
+ return mNextUpdate;
+ }
+
+ public int getExtensionCount() {
+ return 0;
+ }
+
+ public Extension getExtensionAt(int pos) {
+ return null;
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(new CertID.Template());
+ seqt.addElement(new ANY.Template());
+ seqt.addElement(new GeneralizedTime.Template());
+ seqt.addOptionalElement(new EXPLICIT.Template(
+ new Tag(0), new GeneralizedTime.Template()));
+ seqt.addOptionalElement(new EXPLICIT.Template(new Tag(1),
+ new SEQUENCE.OF_Template(new Extension.Template())));
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ istream);
+
+ CertID cid = (CertID) seq.elementAt(0);
+ CertStatus status = null;
+ ANY e_status = (ANY) seq.elementAt(1);
+ if (e_status.getTag().getNum() == 0) {
+ status = (GoodInfo)
+ GoodInfo.getTemplate().decode(
+ e_status.getTag(),
+ new ByteArrayInputStream(e_status.getEncoded()));
+ // good
+ } else if (e_status.getTag().getNum() == 1) {
+ // revoked
+ status = (RevokedInfo)
+ RevokedInfo.getTemplate().decode(
+ e_status.getTag(),
+ new ByteArrayInputStream(e_status.getEncoded()));
+ } else if (e_status.getTag().getNum() == 2) {
+ // unknown
+ status = (UnknownInfo)
+ UnknownInfo.getTemplate().decode(
+ e_status.getTag(),
+ new ByteArrayInputStream(e_status.getEncoded()));
+ }
+ GeneralizedTime thisUpdate = (GeneralizedTime)
+ seq.elementAt(2);
+ GeneralizedTime nextUpdate = null;
+
+ return new SingleResponse(cid, status, thisUpdate,
+ nextUpdate);
+
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/TBSRequest.java b/base/util/src/com/netscape/cmsutil/ocsp/TBSRequest.java
new file mode 100644
index 000000000..b7f706edb
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/TBSRequest.java
@@ -0,0 +1,210 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.pkix.cert.Extension;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class TBSRequest implements ASN1Value {
+ ///////////////////////////////////////////////////////////////////////
+ // members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private static final INTEGER v1 = new INTEGER(0);
+ private INTEGER version;
+ private ANY requestorName;
+ private SEQUENCE requestList;
+ private SEQUENCE requestExtensions;
+
+ public INTEGER getVersion() {
+ return version;
+ }
+
+ public ANY getRequestorName() {
+ return requestorName;
+ }
+
+ public int getRequestCount() {
+ if (requestList == null) {
+ return 0;
+ } else {
+ return requestList.size();
+ }
+ }
+
+ public Request getRequestAt(int index) {
+ return (Request) requestList.elementAt(index);
+ }
+
+ public int getExtensionsCount() {
+ if (requestExtensions == null) {
+ return 0;
+ } else {
+ return requestExtensions.size();
+ }
+ }
+
+ public Extension getRequestExtensionAt(int index) {
+ return (Extension) requestExtensions.elementAt(index);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // constructors
+ ///////////////////////////////////////////////////////////////////////
+
+ public TBSRequest(INTEGER version, ANY requestorName,
+ SEQUENCE requestList, SEQUENCE requestExtensions) {
+ this.version = (version != null) ? version : v1;
+ this.requestorName = requestorName;
+ this.requestList = requestList;
+ this.requestExtensions = requestExtensions;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // encode / decode
+ ///////////////////////////////////////////////////////////////////////
+ public static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream)
+ throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ SEQUENCE seq = new SEQUENCE();
+
+ if (version != v1) {
+ seq.addElement(new EXPLICIT(Tag.get(0), version));
+ }
+
+ if (requestorName != null) {
+ seq.addElement(new EXPLICIT(Tag.get(1), requestorName));
+ }
+
+ seq.addElement(requestList);
+
+ if (requestExtensions != null) {
+ seq.addElement(new EXPLICIT(Tag.get(2), requestExtensions));
+ }
+ if (implicitTag == null) {
+ seq.encode(ostream);
+ } else {
+ seq.encode(implicitTag, ostream);
+ }
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding TBSRequest.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement(
+ new EXPLICIT.Template(
+ new Tag(0), new INTEGER.Template()),
+ new EXPLICIT(new Tag(0), new INTEGER(0))
+ );
+ seqt.addOptionalElement(
+ new EXPLICIT.Template(
+ new Tag(1), new ANY.Template()));
+ seqt.addElement(new SEQUENCE.OF_Template(new Request.Template()));
+ seqt.addOptionalElement(new EXPLICIT.Template(new Tag(2),
+ new SEQUENCE.OF_Template(new Extension.Template())));
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ INTEGER v = v1; //assume default version
+ EXPLICIT e_ver = (EXPLICIT) seq.elementAt(0);
+ if (e_ver != null) {
+ v = (INTEGER) e_ver.getContent();
+ }
+
+ ANY requestorname = null;
+ EXPLICIT e_requestorName = (EXPLICIT) seq.elementAt(1);
+ if (e_requestorName != null) {
+ requestorname = (ANY) e_requestorName.getContent();
+ }
+
+ //request sequence (element 2) done below
+
+ EXPLICIT exts = (EXPLICIT) seq.elementAt(3);
+ SEQUENCE exts_seq;
+ if (exts != null) {
+ exts_seq = (SEQUENCE) exts.getContent();
+ } else {
+ exts_seq = null;
+ }
+
+ return new TBSRequest(
+ v,
+ requestorname,
+ (SEQUENCE) seq.elementAt(2),
+ exts_seq);
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/UnknownInfo.java b/base/util/src/com/netscape/cmsutil/ocsp/UnknownInfo.java
new file mode 100644
index 000000000..1fe4ea743
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/ocsp/UnknownInfo.java
@@ -0,0 +1,95 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.NULL;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * RFC 2560:
+ *
+ * <pre>
+ * UnknownInfo ::= NULL -- this can be replaced with an enumeration
+ * </pre>
+ *
+ * @version $Revision$ $Date$
+ */
+public class UnknownInfo implements CertStatus {
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public UnknownInfo() {
+ }
+
+ public Tag getTag() {
+ return Tag.get(2);
+ }
+
+ public void encode(Tag t, OutputStream os) throws IOException {
+ NULL.getInstance().encode(getTag(), os);
+ }
+
+ public void encode(OutputStream os) throws IOException {
+ encode(getTag(), os);
+ }
+
+ private static final Template templateInstance = new Template();
+
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A Template for decoding <code>ResponseBytes</code>.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ // seqt = new SEQUENCE.Template();
+ // seqt.addElement(new NULL.Template() );
+
+ }
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException {
+ // SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag,
+ // istream);
+
+ return new UnknownInfo();
+
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/IPasswordReader.java b/base/util/src/com/netscape/cmsutil/password/IPasswordReader.java
new file mode 100644
index 000000000..759e9e777
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/IPasswordReader.java
@@ -0,0 +1,29 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public interface IPasswordReader {
+ public void init(String pwdPath) throws IOException;
+
+ public String getPassword(String tag);
+
+ public Enumeration<String> getTags();
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/IPasswordStore.java b/base/util/src/com/netscape/cmsutil/password/IPasswordStore.java
new file mode 100644
index 000000000..49b2610fa
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/IPasswordStore.java
@@ -0,0 +1,34 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public interface IPasswordStore {
+ public void init(String pwdPath) throws IOException;
+
+ public String getPassword(String tag);
+
+ public Enumeration<String> getTags();
+
+ public Object putPassword(String tag, String password);
+
+ public void commit()
+ throws IOException, ClassCastException, NullPointerException;
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/IPasswordWriter.java b/base/util/src/com/netscape/cmsutil/password/IPasswordWriter.java
new file mode 100644
index 000000000..c9f9691e7
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/IPasswordWriter.java
@@ -0,0 +1,30 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.IOException;
+
+public interface IPasswordWriter {
+ public void init(String pwdPath)
+ throws IOException;;
+
+ public Object putPassword(String tag, String password);
+
+ public void commit()
+ throws IOException, ClassCastException, NullPointerException;
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/PlainPasswordFile.java b/base/util/src/com/netscape/cmsutil/password/PlainPasswordFile.java
new file mode 100644
index 000000000..eb43607f0
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/PlainPasswordFile.java
@@ -0,0 +1,70 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+
+public class PlainPasswordFile implements IPasswordStore {
+ private String mPwdPath = "";
+ private Properties mPwdStore;
+ private static final String PASSWORD_WRITER_HEADER = "";
+
+ public PlainPasswordFile() {
+ }
+
+ public void init(String pwdPath)
+ throws IOException {
+ mPwdStore = new Properties();
+ // initialize mPwdStore
+ mPwdPath = pwdPath;
+
+ FileInputStream file = new FileInputStream(mPwdPath);
+ mPwdStore.load(file);
+ file.close();
+ }
+
+ public String getPassword(String tag) {
+ return (String) mPwdStore.getProperty(tag);
+ }
+
+ // return an array of String-based tag
+ public Enumeration<String> getTags() {
+ Enumeration<?> e = mPwdStore.propertyNames();
+ Vector<String> v = new Vector<String>();
+ while (e.hasMoreElements()) {
+ v.add((String) e.nextElement());
+ }
+ return v.elements();
+ }
+
+ public Object putPassword(String tag, String password) {
+ return mPwdStore.setProperty(tag, password);
+ }
+
+ public void commit()
+ throws IOException, ClassCastException, NullPointerException {
+ FileOutputStream file = new FileOutputStream(mPwdPath);
+ mPwdStore.store(file, PASSWORD_WRITER_HEADER);
+ file.close();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/PlainPasswordReader.java b/base/util/src/com/netscape/cmsutil/password/PlainPasswordReader.java
new file mode 100644
index 000000000..68724a9f6
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/PlainPasswordReader.java
@@ -0,0 +1,58 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+
+public class PlainPasswordReader implements IPasswordReader {
+ private String mPwdPath = "";
+ private Properties mPwdStore;
+
+ public PlainPasswordReader() {
+ }
+
+ public void init(String pwdPath)
+ throws IOException {
+ mPwdStore = new Properties();
+ // initialize mPwdStore
+ mPwdPath = pwdPath;
+ mPwdStore = new Properties();
+
+ FileInputStream file = new FileInputStream(mPwdPath);
+ mPwdStore.load(file);
+ file.close();
+ }
+
+ public String getPassword(String tag) {
+ return (String) mPwdStore.getProperty(tag);
+ }
+
+ // return an array of String-based tag
+ public Enumeration<String> getTags() {
+ Enumeration<?> e = mPwdStore.propertyNames();
+ Vector<String> v = new Vector<String>();
+ while (e.hasMoreElements()) {
+ v.add((String) e.nextElement());
+ }
+ return v.elements();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/password/PlainPasswordWriter.java b/base/util/src/com/netscape/cmsutil/password/PlainPasswordWriter.java
new file mode 100644
index 000000000..3ceac4bd6
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/password/PlainPasswordWriter.java
@@ -0,0 +1,56 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.password;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class PlainPasswordWriter implements IPasswordWriter {
+ private static final String PASSWORD_WRITER_HEADER = "";
+ private String mPwdPath = "";
+ private Properties mPwdStore;
+
+ public PlainPasswordWriter() {
+ }
+
+ public void init(String pwdPath)
+ throws IOException {
+ mPwdStore = new Properties();
+ // initialize mPwdStore
+ mPwdPath = pwdPath;
+ mPwdStore = new Properties();
+
+ FileInputStream file = new FileInputStream(mPwdPath);
+ mPwdStore.load(file);
+ file.close();
+ }
+
+ public Object putPassword(String tag, String password) {
+ return mPwdStore.setProperty(tag, password);
+ }
+
+ public void commit()
+ throws IOException, ClassCastException, NullPointerException {
+ FileOutputStream file = new FileOutputStream(mPwdPath);
+ mPwdStore.store(file, PASSWORD_WRITER_HEADER);
+ file.close();
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AccessAccept.java b/base/util/src/com/netscape/cmsutil/radius/AccessAccept.java
new file mode 100644
index 000000000..4824c885f
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AccessAccept.java
@@ -0,0 +1,27 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class AccessAccept extends ServerPacket {
+ public AccessAccept(byte data[]) throws IOException {
+ super(data);
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AccessChallenge.java b/base/util/src/com/netscape/cmsutil/radius/AccessChallenge.java
new file mode 100644
index 000000000..c06f809b1
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AccessChallenge.java
@@ -0,0 +1,27 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class AccessChallenge extends ServerPacket {
+ public AccessChallenge(byte data[]) throws IOException {
+ super(data);
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AccessReject.java b/base/util/src/com/netscape/cmsutil/radius/AccessReject.java
new file mode 100644
index 000000000..5f32ef349
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AccessReject.java
@@ -0,0 +1,27 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class AccessReject extends ServerPacket {
+ public AccessReject(byte data[]) throws IOException {
+ super(data);
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AccessRequest.java b/base/util/src/com/netscape/cmsutil/radius/AccessRequest.java
new file mode 100644
index 000000000..7856b0cc8
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AccessRequest.java
@@ -0,0 +1,25 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+public class AccessRequest extends NASPacket {
+ public AccessRequest(short id, Authenticator auth) {
+ super(ACCESS_REQUEST, id, auth);
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/Attribute.java b/base/util/src/com/netscape/cmsutil/radius/Attribute.java
new file mode 100644
index 000000000..5e79816e4
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/Attribute.java
@@ -0,0 +1,97 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public abstract class Attribute {
+ public static final int USER_NAME = 1;
+ public static final int USER_PASSWORD = 2;
+ public static final int CHAP_PASSWORD = 3;
+ public static final int NAS_IP_ADDRESS = 4;
+ public static final int NAS_PORT = 5;
+ public static final int SERVICE_TYPE = 6;
+ public static final int FRAMED_PROTOCOL = 7;
+ public static final int FRAMED_IP_ADDRESS = 8;
+ public static final int FRAMED_IP_NETMASK = 9;
+ public static final int FRAMED_ROUTING = 10;
+ public static final int FILTER_ID = 11;
+ public static final int FRAMED_MTU = 12;
+ public static final int FRAMED_COMPRESSION = 13;
+ public static final int LOGIN_IP_HOST = 14;
+ public static final int LOGIN_SERVICE = 15;
+ public static final int LOGIN_TCP_PORT = 16;
+ // 17 HAS NOT BEEN ASSIGNED
+ public static final int REPLY_MESSAGE = 18;
+ public static final int CALLBACK_NUMBER = 19;
+ public static final int CALLBACK_ID = 20;
+ // 21 HAS NOT BEEN ASSIGNED
+ public static final int FRAMED_ROUTE = 22;
+ public static final int FRAMED_IPX_NETWORK = 23;
+ public static final int STATE = 24;
+ public static final int NAS_CLASS = 25;
+ public static final int VENDOR_SPECIFIC = 26;
+ public static final int SESSION_TIMEOUT = 27;
+ public static final int IDLE_TIMEOUT = 28;
+ public static final int TERMINATION_ACTION = 29;
+ public static final int CALLER_STATION_ID = 30;
+ public static final int CALLING_STATION_ID = 31;
+ public static final int NAS_IDENTIFIER = 32;
+ public static final int PROXY_STATE = 33;
+ public static final int LOGIN_LAT_SERVICE = 34;
+ public static final int LOGIN_LAT_NODE = 35;
+ public static final int LOGIN_LAT_GROUP = 36;
+ public static final int FRAMED_APPLETALK_LINK = 37;
+ public static final int FRAMED_APPLETALK_NETWORK = 38;
+ public static final int FRAMED_APPLETALK_ZONE = 39;
+ // 40-59 HAS NOT BEEN ASSIGNED
+ public static final int CHAP_CHALLENGE = 60;
+ public static final int NAS_PORT_TYPE = 61;
+ public static final int PORT_LIMIT = 62;
+ public static final int LOGIN_LAT_PORT = 63;
+
+ protected int _t = 0;
+
+ public Attribute() {
+ }
+
+ public Attribute(int t) {
+ _t = t;
+ }
+
+ public int getType() {
+ return _t;
+ }
+
+ public abstract byte[] getValue()
+ throws IOException;
+
+ public byte[] getData()
+ throws IOException {
+ ByteArrayOutputStream attrOS = new ByteArrayOutputStream();
+
+ attrOS.write(_t); // type
+ byte value[] = getValue();
+
+ attrOS.write(value.length + 2); // length
+ attrOS.write(value);
+
+ return attrOS.toByteArray();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AttributeFactory.java b/base/util/src/com/netscape/cmsutil/radius/AttributeFactory.java
new file mode 100644
index 000000000..021c06720
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AttributeFactory.java
@@ -0,0 +1,154 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class AttributeFactory {
+ public static Attribute createAttribute(byte data[])
+ throws IOException {
+ switch (data[0] & 0xFF) {
+ case Attribute.USER_NAME: // 1
+ return new UserNameAttribute(data);
+
+ case Attribute.USER_PASSWORD: // 2
+ return new UserPasswordAttribute(data);
+
+ case Attribute.NAS_IP_ADDRESS: // 4
+ return new NASIPAddressAttribute(data);
+
+ case Attribute.NAS_PORT: // 5
+ return new NASPortAttribute(data);
+
+ case Attribute.CHAP_PASSWORD: // 3
+ return new CHAPPasswordAttribute(data);
+
+ case Attribute.SERVICE_TYPE: // 6
+ return new ServiceTypeAttribute(data);
+
+ case Attribute.FRAMED_PROTOCOL: // 7
+ return new FramedProtocolAttribute(data);
+
+ case Attribute.FRAMED_IP_ADDRESS: // 8
+ return new FramedIPAddressAttribute(data);
+
+ case Attribute.FRAMED_IP_NETMASK: // 9
+ return new FramedIPNetmaskAttribute(data);
+
+ case Attribute.FRAMED_ROUTING: // 10
+ return new FramedRoutingAttribute(data);
+
+ case Attribute.FILTER_ID: // 11
+ return new FilterIdAttribute(data);
+
+ case Attribute.FRAMED_MTU: // 12
+ return new FramedMTUAttribute(data);
+
+ case Attribute.FRAMED_COMPRESSION: // 13
+ return new FramedCompressionAttribute(data);
+
+ case Attribute.LOGIN_IP_HOST: // 14
+ return new LoginIPHostAttribute(data);
+
+ case Attribute.LOGIN_SERVICE: // 15
+ return new LoginServiceAttribute(data);
+
+ case Attribute.LOGIN_TCP_PORT: // 16
+ return new LoginTCPPortAttribute(data);
+
+ case Attribute.REPLY_MESSAGE: // 18
+ return new ReplyMessageAttribute(data);
+
+ case Attribute.CALLBACK_NUMBER: // 19
+ return new CallbackNumberAttribute(data);
+
+ case Attribute.CALLBACK_ID: // 20
+ return new CallbackIdAttribute(data);
+
+ case Attribute.FRAMED_ROUTE: // 22
+ return new FramedRouteAttribute(data);
+
+ case Attribute.FRAMED_IPX_NETWORK: // 23
+ return new FramedIPXNetworkAttribute(data);
+
+ case Attribute.STATE: // 24
+ return new StateAttribute(data);
+
+ case Attribute.NAS_CLASS: // 25
+ return new NASClassAttribute(data);
+
+ case Attribute.VENDOR_SPECIFIC: // 26
+ return new VendorSpecificAttribute(data);
+
+ case Attribute.SESSION_TIMEOUT: // 27
+ return new SessionTimeoutAttribute(data);
+
+ case Attribute.IDLE_TIMEOUT: // 28
+ return new IdleTimeoutAttribute(data);
+
+ case Attribute.TERMINATION_ACTION: // 29
+ return new TerminationActionAttribute(data);
+
+ case Attribute.CALLER_STATION_ID: // 30
+ return new CallerStationIdAttribute(data);
+
+ case Attribute.CALLING_STATION_ID: // 31
+ return new CallingStationIdAttribute(data);
+
+ case Attribute.NAS_IDENTIFIER: // 32
+ return new NASIdentifierAttribute(data);
+
+ case Attribute.PROXY_STATE: // 33
+ return new ProxyStateAttribute(data);
+
+ case Attribute.LOGIN_LAT_SERVICE: // 34
+ return new LoginLATServiceAttribute(data);
+
+ case Attribute.LOGIN_LAT_NODE: // 35
+ return new LoginLATNodeAttribute(data);
+
+ case Attribute.LOGIN_LAT_GROUP: // 36
+ return new LoginLATGroupAttribute(data);
+
+ case Attribute.FRAMED_APPLETALK_LINK: // 37
+ return new FramedAppleTalkLinkAttribute(data);
+
+ case Attribute.FRAMED_APPLETALK_NETWORK: // 38
+ return new FramedAppleTalkNetworkAttribute(data);
+
+ case Attribute.FRAMED_APPLETALK_ZONE: // 39
+ return new FramedAppleTalkZoneAttribute(data);
+
+ case Attribute.CHAP_CHALLENGE: // 60
+ return new CHAPChallengeAttribute(data);
+
+ case Attribute.NAS_PORT_TYPE: // 61
+ return new NASPortTypeAttribute(data);
+
+ case Attribute.PORT_LIMIT: // 62
+ return new PortLimitAttribute(data);
+
+ case Attribute.LOGIN_LAT_PORT: // 63
+ return new LoginLATPortAttribute(data);
+
+ default:
+ return new GenericAttribute(data);
+ // throw new IOException("Unknown attribute " + (data[0] & 0xFF));
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/AttributeSet.java b/base/util/src/com/netscape/cmsutil/radius/AttributeSet.java
new file mode 100644
index 000000000..d6974d371
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/AttributeSet.java
@@ -0,0 +1,56 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class AttributeSet {
+ private Vector<Attribute> _attrs = new Vector<Attribute>();
+
+ public AttributeSet() {
+ }
+
+ public void addAttribute(Attribute attr) {
+ _attrs.addElement(attr);
+ }
+
+ public int size() {
+ return _attrs.size();
+ }
+
+ public Enumeration<Attribute> getAttributes() {
+ return _attrs.elements();
+ }
+
+ public Attribute getAttributeByType(int type) {
+ int l = _attrs.size();
+
+ for (int i = 0; i < l; i++) {
+ Attribute attr = getAttributeAt(i);
+
+ if (attr.getType() == type)
+ return attr;
+ }
+ return null;
+ }
+
+ public Attribute getAttributeAt(int pos) {
+ return _attrs.elementAt(pos);
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/Authenticator.java b/base/util/src/com/netscape/cmsutil/radius/Authenticator.java
new file mode 100644
index 000000000..008af489a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/Authenticator.java
@@ -0,0 +1,24 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public abstract class Authenticator {
+ public abstract byte[] getData() throws IOException;
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CHAPChallengeAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CHAPChallengeAttribute.java
new file mode 100644
index 000000000..cd715a031
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CHAPChallengeAttribute.java
@@ -0,0 +1,38 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CHAPChallengeAttribute extends Attribute {
+ private String _str = null;
+
+ public CHAPChallengeAttribute(byte value[]) {
+ super();
+ _t = CHAP_CHALLENGE;
+ _str = new String(value, 2, value.length - 2);
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CHAPPasswordAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CHAPPasswordAttribute.java
new file mode 100644
index 000000000..3f0ef1793
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CHAPPasswordAttribute.java
@@ -0,0 +1,55 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CHAPPasswordAttribute extends Attribute {
+ private byte _value[] = null;
+ private int _ident = 0;
+ private String _str = null;
+
+ public CHAPPasswordAttribute(String s) {
+ _str = s;
+ }
+
+ public CHAPPasswordAttribute(byte value[]) {
+ super();
+ _t = CHAP_PASSWORD;
+ _ident = value[2];
+ _str = new String(value, 2, 16);
+ _value = value;
+ }
+
+ public int getIdent() {
+ return _ident;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte val[] = new byte[1 + _str.length()];
+ byte s[] = _str.getBytes();
+
+ val[0] = (byte) _ident;
+ System.arraycopy(s, 0, val, 1, s.length);
+ return val;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CallbackIdAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CallbackIdAttribute.java
new file mode 100644
index 000000000..5fd806003
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CallbackIdAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CallbackIdAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public CallbackIdAttribute(byte value[]) {
+ super();
+ _t = CALLBACK_ID;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CallbackNumberAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CallbackNumberAttribute.java
new file mode 100644
index 000000000..d6e45cecd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CallbackNumberAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CallbackNumberAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public CallbackNumberAttribute(byte value[]) {
+ super();
+ _t = CALLBACK_NUMBER;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CallerStationIdAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CallerStationIdAttribute.java
new file mode 100644
index 000000000..3b5eec804
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CallerStationIdAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CallerStationIdAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public CallerStationIdAttribute(byte value[]) {
+ super();
+ _t = CALLER_STATION_ID;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/CallingStationIdAttribute.java b/base/util/src/com/netscape/cmsutil/radius/CallingStationIdAttribute.java
new file mode 100644
index 000000000..9a57f8089
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/CallingStationIdAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class CallingStationIdAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public CallingStationIdAttribute(byte value[]) {
+ super();
+ _t = CALLING_STATION_ID;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ChallengeException.java b/base/util/src/com/netscape/cmsutil/radius/ChallengeException.java
new file mode 100644
index 000000000..972f7f084
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ChallengeException.java
@@ -0,0 +1,43 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+public class ChallengeException extends Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3496050461777520369L;
+ private AccessChallenge _res = null;
+
+ public ChallengeException(AccessChallenge res) {
+ _res = res;
+ }
+
+ public AttributeSet getAttributeSet() {
+ return _res.getAttributeSet();
+ }
+
+ public String getState() {
+ return ((StateAttribute) (_res.getAttributeSet().getAttributeByType(Attribute.STATE))).getString();
+ }
+
+ public String getReplyMessage() {
+ return ((ReplyMessageAttribute) (_res.getAttributeSet().getAttributeByType(Attribute.REPLY_MESSAGE)))
+ .getString();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FilterIdAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FilterIdAttribute.java
new file mode 100644
index 000000000..879d7d5c7
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FilterIdAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FilterIdAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public FilterIdAttribute(byte value[]) {
+ super();
+ _t = CHAP_PASSWORD;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkLinkAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkLinkAttribute.java
new file mode 100644
index 000000000..05273780f
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkLinkAttribute.java
@@ -0,0 +1,51 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedAppleTalkLinkAttribute extends Attribute {
+ public static int UN_NUMBERED = 0;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedAppleTalkLinkAttribute(byte value[]) {
+ super();
+ _t = FRAMED_APPLETALK_LINK;
+ _value = value;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkNetworkAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkNetworkAttribute.java
new file mode 100644
index 000000000..cea0d936a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkNetworkAttribute.java
@@ -0,0 +1,49 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedAppleTalkNetworkAttribute extends Attribute {
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedAppleTalkNetworkAttribute(byte value[]) {
+ super();
+ _t = FRAMED_APPLETALK_NETWORK;
+ _value = value;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkZoneAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkZoneAttribute.java
new file mode 100644
index 000000000..54ee47c45
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedAppleTalkZoneAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedAppleTalkZoneAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public FramedAppleTalkZoneAttribute(byte value[]) {
+ super();
+ _t = FRAMED_APPLETALK_ZONE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedCompressionAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedCompressionAttribute.java
new file mode 100644
index 000000000..b57c030b5
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedCompressionAttribute.java
@@ -0,0 +1,54 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedCompressionAttribute extends Attribute {
+ public static final int NONE = 1;
+ public static final int VJ_TCP_IP_HEADER = 2;
+ public static final int IPX_HEADER = 2;
+ public static final int STAC_LZS = 3;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedCompressionAttribute(byte value[]) {
+ super();
+ _t = FRAMED_COMPRESSION;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedIPAddressAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedIPAddressAttribute.java
new file mode 100644
index 000000000..2f66ee8c2
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedIPAddressAttribute.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedIPAddressAttribute extends Attribute {
+ private byte _value[] = null;
+ private byte _addr[] = new byte[4];
+
+ public FramedIPAddressAttribute(byte value[]) {
+ super();
+ _t = FRAMED_IP_ADDRESS;
+ _addr[0] = value[2];
+ _addr[1] = value[3];
+ _addr[2] = value[4];
+ _addr[3] = value[5];
+ _value = value;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _addr;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedIPNetmaskAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedIPNetmaskAttribute.java
new file mode 100644
index 000000000..f8e1980c7
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedIPNetmaskAttribute.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedIPNetmaskAttribute extends Attribute {
+ private byte _value[] = null;
+ private byte _mask[] = new byte[4];
+
+ public FramedIPNetmaskAttribute(byte value[]) {
+ super();
+ _t = FRAMED_IP_NETMASK;
+ _mask[0] = value[2];
+ _mask[1] = value[3];
+ _mask[2] = value[4];
+ _mask[3] = value[5];
+ _value = value;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _mask;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedIPXNetworkAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedIPXNetworkAttribute.java
new file mode 100644
index 000000000..92f47eec1
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedIPXNetworkAttribute.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedIPXNetworkAttribute extends Attribute {
+ private byte _value[] = null;
+ private byte _net[] = new byte[4];
+
+ public FramedIPXNetworkAttribute(byte value[]) {
+ super();
+ _t = FRAMED_IPX_NETWORK;
+ _net[0] = value[2];
+ _net[1] = value[3];
+ _net[2] = value[4];
+ _net[3] = value[5];
+ _value = value;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _net;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedMTUAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedMTUAttribute.java
new file mode 100644
index 000000000..5cd9551a2
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedMTUAttribute.java
@@ -0,0 +1,49 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedMTUAttribute extends Attribute {
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedMTUAttribute(byte value[]) {
+ super();
+ _t = FRAMED_IP_ADDRESS;
+ _value = value;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedProtocolAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedProtocolAttribute.java
new file mode 100644
index 000000000..5af219b9a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedProtocolAttribute.java
@@ -0,0 +1,56 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedProtocolAttribute extends Attribute {
+ public static final int PPP = 1;
+ public static final int SLIP = 2;
+ public static final int ARAP = 3;
+ public static final int GANDALF = 4;
+ public static final int XYLOGICS = 5;
+ public static final int X_75 = 6;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedProtocolAttribute(byte value[]) {
+ super();
+ _t = SERVICE_TYPE;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedRouteAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedRouteAttribute.java
new file mode 100644
index 000000000..9b123fe2a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedRouteAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedRouteAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public FramedRouteAttribute(byte value[]) {
+ super();
+ _t = FRAMED_ROUTE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/FramedRoutingAttribute.java b/base/util/src/com/netscape/cmsutil/radius/FramedRoutingAttribute.java
new file mode 100644
index 000000000..14d2b0cc8
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/FramedRoutingAttribute.java
@@ -0,0 +1,54 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class FramedRoutingAttribute extends Attribute {
+ public static final int NONE = 0;
+ public static final int SEND_ROUTING_PACKETS = 1;
+ public static final int LISTEN_FOR_ROUTING_PACKETS = 2;
+ public static final int SEND_AND_LISTEN = 3;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public FramedRoutingAttribute(byte value[]) {
+ super();
+ _t = FRAMED_ROUTING;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/GenericAttribute.java b/base/util/src/com/netscape/cmsutil/radius/GenericAttribute.java
new file mode 100644
index 000000000..ac1798ae3
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/GenericAttribute.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class GenericAttribute extends Attribute {
+ private byte _value[] = null;
+
+ public GenericAttribute(byte value[]) {
+ super();
+ _t = value[0];
+ _value = new byte[value.length - 2];
+ System.arraycopy(value, 2, _value, 0, _value.length);
+ }
+
+ public byte[] getValue() throws IOException {
+ return _value;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/IdleTimeoutAttribute.java b/base/util/src/com/netscape/cmsutil/radius/IdleTimeoutAttribute.java
new file mode 100644
index 000000000..44b0c5087
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/IdleTimeoutAttribute.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class IdleTimeoutAttribute extends Attribute {
+ private int _timeout = 0;
+
+ public IdleTimeoutAttribute(byte value[]) {
+ super();
+ _t = IDLE_TIMEOUT;
+ _timeout = value[5] & 0xFF;
+ _timeout |= ((value[4] << 8) & 0xFF00);
+ _timeout |= ((value[3] << 16) & 0xFF0000);
+ _timeout |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public IdleTimeoutAttribute(int timeout) {
+ super(IDLE_TIMEOUT);
+ _timeout = timeout;
+ }
+
+ public int getTimeout() {
+ return _timeout;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_timeout >>> 24) & 0xFF);
+ p[1] = (byte) ((_timeout >>> 16) & 0xFF);
+ p[2] = (byte) ((_timeout >>> 8) & 0xFF);
+ p[3] = (byte) (_timeout & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginIPHostAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginIPHostAttribute.java
new file mode 100644
index 000000000..0d1c0565a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginIPHostAttribute.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginIPHostAttribute extends Attribute {
+ public static final int NAS_ALLOW_SELECT = 0xFFFFFFFF;
+ public static final int NAS_SELECT = 0;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public LoginIPHostAttribute(byte value[]) {
+ super();
+ _t = LOGIN_IP_HOST;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginLATGroupAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginLATGroupAttribute.java
new file mode 100644
index 000000000..4cee6bc3a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginLATGroupAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginLATGroupAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public LoginLATGroupAttribute(byte value[]) {
+ super();
+ _t = LOGIN_LAT_GROUP;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginLATNodeAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginLATNodeAttribute.java
new file mode 100644
index 000000000..2c2d3411e
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginLATNodeAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginLATNodeAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public LoginLATNodeAttribute(byte value[]) {
+ super();
+ _t = LOGIN_LAT_NODE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginLATPortAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginLATPortAttribute.java
new file mode 100644
index 000000000..330161ec8
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginLATPortAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginLATPortAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public LoginLATPortAttribute(byte value[]) {
+ super();
+ _t = PROXY_STATE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginLATServiceAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginLATServiceAttribute.java
new file mode 100644
index 000000000..158630d27
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginLATServiceAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginLATServiceAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public LoginLATServiceAttribute(byte value[]) {
+ super();
+ _t = LOGIN_LAT_SERVICE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginServiceAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginServiceAttribute.java
new file mode 100644
index 000000000..73f49d39f
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginServiceAttribute.java
@@ -0,0 +1,58 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginServiceAttribute extends Attribute {
+ public static final int TELNET = 0;
+ public static final int RLOGIN = 1;
+ public static final int TCP_CLEAR = 2;
+ public static final int PORTMASTER = 3;
+ public static final int LAT = 4;
+ public static final int X25_PAD = 5;
+ public static final int X25_T3POS = 6;
+ public static final int TCP_CLEAR_QUIET = 8;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public LoginServiceAttribute(byte value[]) {
+ super();
+ _t = LOGIN_SERVICE;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/LoginTCPPortAttribute.java b/base/util/src/com/netscape/cmsutil/radius/LoginTCPPortAttribute.java
new file mode 100644
index 000000000..6b44f50c6
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/LoginTCPPortAttribute.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class LoginTCPPortAttribute extends Attribute {
+ private int _port = 0;
+
+ public LoginTCPPortAttribute(byte value[]) {
+ super();
+ _t = LOGIN_TCP_PORT;
+ _port = value[5] & 0xFF;
+ _port |= ((value[4] << 8) & 0xFF00);
+ _port |= ((value[3] << 16) & 0xFF0000);
+ _port |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public LoginTCPPortAttribute(int port) {
+ super(LOGIN_TCP_PORT);
+ _port = port;
+ }
+
+ public int getPort() {
+ return _port;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_port >>> 24) & 0xFF);
+ p[1] = (byte) ((_port >>> 16) & 0xFF);
+ p[2] = (byte) ((_port >>> 8) & 0xFF);
+ p[3] = (byte) (_port & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASClassAttribute.java b/base/util/src/com/netscape/cmsutil/radius/NASClassAttribute.java
new file mode 100644
index 000000000..57b983028
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASClassAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class NASClassAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public NASClassAttribute(byte value[]) {
+ super();
+ _t = NAS_CLASS;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASIPAddressAttribute.java b/base/util/src/com/netscape/cmsutil/radius/NASIPAddressAttribute.java
new file mode 100644
index 000000000..d4022b3dd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASIPAddressAttribute.java
@@ -0,0 +1,41 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+public class NASIPAddressAttribute extends Attribute {
+ private InetAddress _ip = null;
+ private byte _value[] = null;
+
+ public NASIPAddressAttribute(byte value[]) {
+ super();
+ _t = NAS_IP_ADDRESS;
+ _value = value;
+ }
+
+ public NASIPAddressAttribute(InetAddress ip) {
+ super(NAS_IP_ADDRESS);
+ _ip = ip;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _ip.getAddress();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASIdentifierAttribute.java b/base/util/src/com/netscape/cmsutil/radius/NASIdentifierAttribute.java
new file mode 100644
index 000000000..0a3a62cd8
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASIdentifierAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class NASIdentifierAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public NASIdentifierAttribute(byte value[]) {
+ super();
+ _t = NAS_IDENTIFIER;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASPacket.java b/base/util/src/com/netscape/cmsutil/radius/NASPacket.java
new file mode 100644
index 000000000..70d143989
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASPacket.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public abstract class NASPacket extends Packet {
+ public NASPacket(int c, short id, Authenticator auth) {
+ super(c, id, auth);
+ }
+
+ public byte[] getData() throws IOException {
+ // prepare the attributes first
+ ByteArrayOutputStream attrsOS = new ByteArrayOutputStream();
+
+ for (int i = 0; i < _attrs.size(); i++) {
+ Attribute attr = (Attribute) getAttributeAt(i);
+
+ attrsOS.write(attr.getData());
+ }
+ byte attrsData[] = attrsOS.toByteArray();
+
+ ByteArrayOutputStream dataOS = new ByteArrayOutputStream();
+
+ dataOS.write(_c); // code
+ dataOS.write(_id); // identifier
+ int len = attrsData.length + 20;
+
+ dataOS.write((len >>> 8) & 0xFF);
+ dataOS.write(len & 0xFF);
+ dataOS.write(_auth.getData());
+ dataOS.write(attrsData);
+
+ return dataOS.toByteArray();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASPortAttribute.java b/base/util/src/com/netscape/cmsutil/radius/NASPortAttribute.java
new file mode 100644
index 000000000..0f7b31e75
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASPortAttribute.java
@@ -0,0 +1,48 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class NASPortAttribute extends Attribute {
+ private int _port = 0;
+
+ public NASPortAttribute(byte value[]) {
+ super();
+ _t = NAS_PORT;
+ _port = value[5] & 0xFF;
+ _port |= ((value[4] << 8) & 0xFF00);
+ _port |= ((value[3] << 16) & 0xFF0000);
+ _port |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public NASPortAttribute(int port) {
+ super(NAS_PORT);
+ _port = port;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_port >>> 24) & 0xFF);
+ p[1] = (byte) ((_port >>> 16) & 0xFF);
+ p[2] = (byte) ((_port >>> 8) & 0xFF);
+ p[3] = (byte) (_port & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/NASPortTypeAttribute.java b/base/util/src/com/netscape/cmsutil/radius/NASPortTypeAttribute.java
new file mode 100644
index 000000000..84ccc3ae1
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/NASPortTypeAttribute.java
@@ -0,0 +1,53 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class NASPortTypeAttribute extends Attribute {
+ public static final int ASYNC = 0;
+ public static final int SYNC = 1;
+ public static final int ISDN_SYNC = 2;
+ public static final int ISDN_ASYNC_V120 = 3;
+ public static final int ISDN_ASYNC_V110 = 4;
+ public static final int VIRTUAL = 5;
+ public static final int PIAFS = 6;
+ public static final int HDLC = 7;
+ public static final int X_25 = 8;
+ public static final int X_75 = 9;
+ public static final int G3_FAX = 10;
+ public static final int SDSL = 11;
+ public static final int ADSL_CAP = 12;
+ public static final int ADSL_DMT = 13;
+ public static final int IDSL = 14;
+ public static final int ETHERNET = 15;
+ public static final int XDSL = 16;
+ public static final int CABLE = 17;
+
+ private byte _value[] = null;
+
+ public NASPortTypeAttribute(byte value[]) {
+ super();
+ _t = NAS_PORT_TYPE;
+ _value = value;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _value;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/Packet.java b/base/util/src/com/netscape/cmsutil/radius/Packet.java
new file mode 100644
index 000000000..4fad0ba79
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/Packet.java
@@ -0,0 +1,70 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+public abstract class Packet {
+ public static final int ACCESS_REQUEST = 1;
+ public static final int ACCESS_ACCEPT = 2;
+ public static final int ACCESS_REJECT = 3;
+ // public static final int ACCOUNTING_REQUEST = 4;
+ // public static final int ACCOUNTING_RESPONSE = 5;
+ public static final int ACCESS_CHALLENGE = 11;
+ public static final int RESERVED = 255;
+
+ protected int _c = 0;
+ protected short _id = 0;
+ protected Authenticator _auth = null;
+ protected AttributeSet _attrs = new AttributeSet();
+
+ public Packet() {
+ }
+
+ public Packet(int c, short id, Authenticator auth) {
+ _c = c;
+ _id = id;
+ _auth = auth;
+ }
+
+ public int getCode() {
+ return _c;
+ }
+
+ public short getIdentifier() {
+ return _id;
+ }
+
+ public Authenticator getAuthenticator() {
+ return _auth;
+ }
+
+ public void addAttribute(Attribute attr) {
+ _attrs.addAttribute(attr);
+ }
+
+ public AttributeSet getAttributeSet() {
+ return _attrs;
+ }
+
+ public Attribute getAttributeAt(int pos) {
+ return _attrs.getAttributeAt(pos);
+ }
+
+ public String toString() {
+ return "Packet [code=" + _c + ",id=" + (_id & 0xFF) + "]";
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/PacketFactory.java b/base/util/src/com/netscape/cmsutil/radius/PacketFactory.java
new file mode 100644
index 000000000..8d2e20e74
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/PacketFactory.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class PacketFactory {
+ public static ServerPacket createServerPacket(byte data[])
+ throws IOException {
+ switch (data[0] & 0xFF) {
+ case Packet.ACCESS_ACCEPT:
+ return new AccessAccept(data);
+
+ case Packet.ACCESS_REJECT:
+ return new AccessReject(data);
+
+ case Packet.ACCESS_CHALLENGE:
+ return new AccessChallenge(data);
+
+ default:
+ throw new IOException("Unknown server packet " + (data[0] & 0xFF));
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/PortLimitAttribute.java b/base/util/src/com/netscape/cmsutil/radius/PortLimitAttribute.java
new file mode 100644
index 000000000..7903bb1fd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/PortLimitAttribute.java
@@ -0,0 +1,51 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class PortLimitAttribute extends Attribute {
+ private int _port = 0;
+
+ private byte _value[] = null;
+
+ public PortLimitAttribute(byte value[]) {
+ super();
+ _t = FRAMED_IP_ADDRESS;
+ _value = value;
+ _port = value[5] & 0xFF;
+ _port |= ((value[4] << 8) & 0xFF00);
+ _port |= ((value[3] << 16) & 0xFF0000);
+ _port |= ((value[2] << 24) & 0xFF000000);
+
+ }
+
+ public int getPort() {
+ return _port;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_port >>> 24) & 0xFF);
+ p[1] = (byte) ((_port >>> 16) & 0xFF);
+ p[2] = (byte) ((_port >>> 8) & 0xFF);
+ p[3] = (byte) (_port & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ProxyStateAttribute.java b/base/util/src/com/netscape/cmsutil/radius/ProxyStateAttribute.java
new file mode 100644
index 000000000..83831b652
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ProxyStateAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class ProxyStateAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public ProxyStateAttribute(byte value[]) {
+ super();
+ _t = PROXY_STATE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/RadiusConn.java b/base/util/src/com/netscape/cmsutil/radius/RadiusConn.java
new file mode 100644
index 000000000..b22807a5d
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/RadiusConn.java
@@ -0,0 +1,230 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Properties;
+
+/**
+ * This class implements RFC2865 - Remote Authentication Dial In
+ * User Service (RADIUS), June 2000.
+ */
+public class RadiusConn {
+ public static int MAX_RETRIES = 10;
+ public static int OFFICAL_PORT = 1812;
+ public static int DEFAULT_PORT = 1645;
+ public static int DEFAULT_TIMEOUT = 5;
+
+ public static String OPTION_DEBUG = "OPTION_DEBUG";
+
+ private Properties _options = null;
+ private boolean _traceOn = true;
+ private String _host[] = new String[2];
+ private int _port[] = new int[2];
+ private int _selected = 0;
+ private String _secret = null;
+ private DatagramSocket _socket = null;
+ private short _id = (short) System.currentTimeMillis();
+ private int _maxRetries = MAX_RETRIES;
+ private SecureRandom _rand = null;
+
+ public RadiusConn(String host1, String host2, int port, String secret,
+ int timeout) throws SocketException {
+ this(host1, port, host2, port, secret, timeout, null, null);
+ }
+
+ public RadiusConn(String host, int port, String secret, byte seed[],
+ Properties options)
+ throws SocketException {
+ this(host, port, host, port, secret, DEFAULT_TIMEOUT, seed, options);
+ }
+
+ public RadiusConn(String host1, int port1, String host2, int port2,
+ String secret, int timeout, byte seed[], Properties options)
+ throws SocketException {
+ _host[0] = host1;
+ _port[0] = port1;
+ _host[1] = host2;
+ _port[1] = port2;
+ _selected = 0;
+ _secret = secret;
+ _options = options;
+ _socket = new DatagramSocket();
+ _socket.setSoTimeout(timeout * 1000);
+ if (seed == null) {
+ _rand = new SecureRandom();
+ } else {
+ _rand = new SecureRandom(seed);
+ }
+ }
+
+ public void disconnect() throws IOException {
+ _socket.disconnect();
+ }
+
+ public void authenticate(String name, String password)
+ throws IOException, NoSuchAlgorithmException,
+ RejectException, ChallengeException {
+ int retries = 0;
+ Packet res = null;
+
+ do {
+ AccessRequest req = createAccessRequest();
+
+ req.addAttribute(new UserNameAttribute(name));
+ req.addAttribute(new UserPasswordAttribute(req.getAuthenticator(),
+ _secret, password));
+ req.addAttribute(new NASIPAddressAttribute(InetAddress.getLocalHost()));
+ req.addAttribute(new NASPortAttribute(_socket.getLocalPort()));
+
+ send(req, _host[_selected], _port[_selected]);
+ try {
+ retries++;
+ res = receive();
+ if (res instanceof AccessReject) {
+ throw new RejectException((AccessReject) res);
+ } else if (res instanceof AccessChallenge) {
+ throw new ChallengeException((AccessChallenge) res);
+ }
+ } catch (InterruptedIOException e) {
+ if (retries >= _maxRetries) {
+ // switch server if maxRetries reaches limit
+ retries = 0;
+ if (_selected == 0) {
+ _selected = 1;
+ } else {
+ _selected = 0;
+ }
+ // throw e;
+ }
+
+ }
+ } while (res == null);
+ }
+
+ public void replyChallenge(String password, ChallengeException ce)
+ throws IOException, NoSuchAlgorithmException,
+ RejectException, ChallengeException {
+ replyChallenge(null, password, ce);
+ }
+
+ public void replyChallenge(String name, String password,
+ ChallengeException ce)
+ throws IOException, NoSuchAlgorithmException,
+ RejectException, ChallengeException {
+ StateAttribute state = (StateAttribute)
+ ce.getAttributeSet().getAttributeByType(Attribute.STATE);
+
+ if (state == null)
+ throw new IOException("State not found in challenge");
+ AccessRequest req = createAccessRequest();
+
+ req.addAttribute(state); // needed in challenge
+ if (name != null) {
+ req.addAttribute(new UserNameAttribute(name));
+ }
+ req.addAttribute(new UserPasswordAttribute(req.getAuthenticator(),
+ _secret, password));
+ req.addAttribute(new NASIPAddressAttribute(InetAddress.getLocalHost()));
+ req.addAttribute(new NASPortAttribute(_socket.getLocalPort()));
+
+ send(req, _host[_selected], _port[_selected]);
+ Packet res = receive();
+
+ if (res instanceof AccessReject) {
+ throw new RejectException((AccessReject) res);
+ } else if (res instanceof AccessChallenge) {
+ throw new ChallengeException((AccessChallenge) res);
+ }
+ }
+
+ public void replyChallenge(String name, String password, String state)
+ throws IOException, NoSuchAlgorithmException,
+ RejectException, ChallengeException {
+ if (state == null)
+ throw new IOException("State not found in challenge");
+ AccessRequest req = createAccessRequest();
+
+ req.addAttribute(new StateAttribute(state)); // needed in challenge
+ req.addAttribute(new UserNameAttribute(name));
+ req.addAttribute(new UserPasswordAttribute(req.getAuthenticator(),
+ _secret, password));
+ req.addAttribute(new NASIPAddressAttribute(InetAddress.getLocalHost()));
+ req.addAttribute(new NASPortAttribute(_socket.getLocalPort()));
+
+ send(req, _host[_selected], _port[_selected]);
+ Packet res = receive();
+
+ if (res instanceof AccessReject) {
+ throw new RejectException((AccessReject) res);
+ } else if (res instanceof AccessChallenge) {
+ throw new ChallengeException((AccessChallenge) res);
+ }
+ }
+
+ private short getIdentifier() {
+ return _id++;
+ }
+
+ private void send(NASPacket packet, String host, int port)
+ throws IOException {
+ DatagramPacket dp = new DatagramPacket(new byte[4096], 4096);
+
+ dp.setPort(port);
+ dp.setAddress(InetAddress.getByName(host));
+ byte data[] = packet.getData();
+
+ dp.setLength(data.length);
+ dp.setData(data);
+ _socket.send(dp);
+ if (_traceOn)
+ trace("Sent " + packet);
+ }
+
+ private ServerPacket receive()
+ throws IOException {
+ DatagramPacket dp = new DatagramPacket(new byte[4096], 4096);
+
+ _socket.receive(dp);
+ byte data[] = dp.getData();
+ ServerPacket p = PacketFactory.createServerPacket(data);
+
+ if (_traceOn)
+ trace("Received " + p + " size=" + p.getAttributeSet().size());
+ return p;
+ }
+
+ private AccessRequest createAccessRequest() throws NoSuchAlgorithmException {
+ RequestAuthenticator ra = new RequestAuthenticator(_rand, _secret);
+ AccessRequest req = new AccessRequest(getIdentifier(), ra);
+
+ return req;
+ }
+
+ private void trace(String msg) {
+ System.out.println("TRACE: " + msg);
+ System.out.flush();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/RejectException.java b/base/util/src/com/netscape/cmsutil/radius/RejectException.java
new file mode 100644
index 000000000..f312ef2a4
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/RejectException.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+public class RejectException extends Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6410697638175895003L;
+ private AccessReject _res = null;
+
+ public RejectException(AccessReject res) {
+ _res = res;
+ }
+
+ public AttributeSet getAttributeSet() {
+ return _res.getAttributeSet();
+ }
+
+ public String getReplyMessage() {
+ return ((ReplyMessageAttribute) (_res.getAttributeSet().getAttributeByType(Attribute.REPLY_MESSAGE)))
+ .getString();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ReplyMessageAttribute.java b/base/util/src/com/netscape/cmsutil/radius/ReplyMessageAttribute.java
new file mode 100644
index 000000000..5ec4ea052
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ReplyMessageAttribute.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class ReplyMessageAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public ReplyMessageAttribute(byte value[]) {
+ super();
+ _t = REPLY_MESSAGE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/RequestAuthenticator.java b/base/util/src/com/netscape/cmsutil/radius/RequestAuthenticator.java
new file mode 100644
index 000000000..5d82752dd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/RequestAuthenticator.java
@@ -0,0 +1,44 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+public class RequestAuthenticator extends Authenticator {
+ private byte _ra[] = null;
+
+ public RequestAuthenticator(SecureRandom rand, String secret)
+ throws NoSuchAlgorithmException {
+ byte[] authenticator = new byte[16];
+
+ rand.nextBytes(authenticator);
+
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+
+ md5.update(authenticator);
+ md5.update(secret.getBytes());
+ _ra = md5.digest();
+ }
+
+ public byte[] getData() throws IOException {
+ return _ra;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ResponseAuthenticator.java b/base/util/src/com/netscape/cmsutil/radius/ResponseAuthenticator.java
new file mode 100644
index 000000000..3c3de33c4
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ResponseAuthenticator.java
@@ -0,0 +1,32 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class ResponseAuthenticator extends Authenticator {
+ private byte _data[] = null;
+
+ public ResponseAuthenticator(byte data[]) {
+ _data = data;
+ }
+
+ public byte[] getData() throws IOException {
+ return _data;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ServerPacket.java b/base/util/src/com/netscape/cmsutil/radius/ServerPacket.java
new file mode 100644
index 000000000..f7d7fa302
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ServerPacket.java
@@ -0,0 +1,47 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public abstract class ServerPacket extends Packet {
+ public ServerPacket(byte data[]) throws IOException {
+ super();
+ _c = data[0];
+ _id = data[1];
+ int datalen = data[3] & 0xFF;
+
+ datalen |= ((data[2] << 8) & 0xFF00);
+ byte authData[] = new byte[16];
+
+ System.arraycopy(data, 4, authData, 0, 16);
+ _auth = new ResponseAuthenticator(authData);
+
+ // building attributes
+ int startp = 20;
+
+ while (startp != datalen) {
+ int attrLen = (data[startp + 1] & 0xFF);
+ byte attrData[] = new byte[attrLen];
+
+ System.arraycopy(data, startp, attrData, 0, attrData.length);
+ addAttribute(AttributeFactory.createAttribute(attrData));
+ startp += attrData.length;
+ }
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/ServiceTypeAttribute.java b/base/util/src/com/netscape/cmsutil/radius/ServiceTypeAttribute.java
new file mode 100644
index 000000000..f31c74f9a
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/ServiceTypeAttribute.java
@@ -0,0 +1,61 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class ServiceTypeAttribute extends Attribute {
+ public static final int LOGIN = 1;
+ public static final int FRAMED = 2;
+ public static final int CALLBACK_LOGIN = 3;
+ public static final int CALLBACK_FRAMED = 4;
+ public static final int OUTBOUND = 5;
+ public static final int ADMINSITRATIVE = 6;
+ public static final int NAS_PROMPT = 7;
+ public static final int AUTHENTICATE_ONLY = 8;
+ public static final int CALLBACK_NAS_PROMPT = 9;
+ public static final int CALL_CHECK = 10;
+ public static final int CALLBACK_ADMINISTRATIVE = 11;
+
+ private byte _value[] = null;
+ private int _type = 0;
+
+ public ServiceTypeAttribute(byte value[]) {
+ super();
+ _t = SERVICE_TYPE;
+ _type = value[5] & 0xFF;
+ _type |= ((value[4] << 8) & 0xFF00);
+ _type |= ((value[3] << 16) & 0xFF0000);
+ _type |= ((value[2] << 24) & 0xFF000000);
+ _value = value;
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_type >>> 24) & 0xFF);
+ p[1] = (byte) ((_type >>> 16) & 0xFF);
+ p[2] = (byte) ((_type >>> 8) & 0xFF);
+ p[3] = (byte) (_type & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/SessionTimeoutAttribute.java b/base/util/src/com/netscape/cmsutil/radius/SessionTimeoutAttribute.java
new file mode 100644
index 000000000..2809aee4b
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/SessionTimeoutAttribute.java
@@ -0,0 +1,48 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class SessionTimeoutAttribute extends Attribute {
+ private int _timeout = 0;
+
+ public SessionTimeoutAttribute(byte value[]) {
+ super();
+ _t = SESSION_TIMEOUT;
+ _timeout = value[5] & 0xFF;
+ _timeout |= ((value[4] << 8) & 0xFF00);
+ _timeout |= ((value[3] << 16) & 0xFF0000);
+ _timeout |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public SessionTimeoutAttribute(int timeout) {
+ super(SESSION_TIMEOUT);
+ _timeout = timeout;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_timeout >>> 24) & 0xFF);
+ p[1] = (byte) ((_timeout >>> 16) & 0xFF);
+ p[2] = (byte) ((_timeout >>> 8) & 0xFF);
+ p[3] = (byte) (_timeout & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/StateAttribute.java b/base/util/src/com/netscape/cmsutil/radius/StateAttribute.java
new file mode 100644
index 000000000..027f95620
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/StateAttribute.java
@@ -0,0 +1,45 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class StateAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _str = null;
+
+ public StateAttribute(String str) {
+ _t = STATE;
+ _str = str;
+ }
+
+ public StateAttribute(byte value[]) {
+ super();
+ _t = STATE;
+ _str = new String(value, 2, value.length - 2);
+ _value = value;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _str.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/TerminationActionAttribute.java b/base/util/src/com/netscape/cmsutil/radius/TerminationActionAttribute.java
new file mode 100644
index 000000000..b47a70d8c
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/TerminationActionAttribute.java
@@ -0,0 +1,55 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class TerminationActionAttribute extends Attribute {
+ public static final int DEFAULT = 0;
+ public static final int RADIUS_REQUEST = 1;
+
+ private int _action = 0;
+
+ public TerminationActionAttribute(byte value[]) {
+ super();
+ _t = TERMINATION_ACTION;
+ _action = value[5] & 0xFF;
+ _action |= ((value[4] << 8) & 0xFF00);
+ _action |= ((value[3] << 16) & 0xFF0000);
+ _action |= ((value[2] << 24) & 0xFF000000);
+ }
+
+ public TerminationActionAttribute(int action) {
+ super(TERMINATION_ACTION);
+ _action = action;
+ }
+
+ public int getAction() {
+ return _action;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte[] p = new byte[4];
+
+ p[0] = (byte) ((_action >>> 24) & 0xFF);
+ p[1] = (byte) ((_action >>> 16) & 0xFF);
+ p[2] = (byte) ((_action >>> 8) & 0xFF);
+ p[3] = (byte) (_action & 0xFF);
+ return p;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/UserNameAttribute.java b/base/util/src/com/netscape/cmsutil/radius/UserNameAttribute.java
new file mode 100644
index 000000000..af7ce6bbe
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/UserNameAttribute.java
@@ -0,0 +1,39 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class UserNameAttribute extends Attribute {
+ private String _name = null;
+
+ public UserNameAttribute(byte value[]) {
+ super();
+ _t = USER_NAME;
+ _name = new String(value, 2, value.length - 2);
+ }
+
+ public UserNameAttribute(String name) {
+ super(USER_NAME);
+ _name = name;
+ }
+
+ public byte[] getValue() throws IOException {
+ return _name.getBytes();
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/UserPasswordAttribute.java b/base/util/src/com/netscape/cmsutil/radius/UserPasswordAttribute.java
new file mode 100644
index 000000000..31c27cdfd
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/UserPasswordAttribute.java
@@ -0,0 +1,73 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class UserPasswordAttribute extends Attribute {
+ private Authenticator _ra = null;
+ private String _secret = null;
+ private String _password = null;
+
+ public UserPasswordAttribute(byte value[]) {
+ //
+ }
+
+ public UserPasswordAttribute(Authenticator ra, String secret, String password) {
+ super(USER_PASSWORD);
+ _ra = ra;
+ _secret = secret;
+ _password = password;
+ }
+
+ public byte[] getValue() throws IOException {
+ MessageDigest md5 = null;
+
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException(e.getMessage());
+ }
+ md5.update(_secret.getBytes());
+ md5.update(_ra.getData());
+ byte sum[] = md5.digest();
+
+ byte up[] = _password.getBytes();
+ int oglen = (up.length / 16) + 1;
+ byte ret[] = new byte[oglen * 16];
+
+ for (int i = 0; i < ret.length; i++) {
+ if ((i % 16) == 0) {
+ md5.reset();
+ md5.update(_secret.getBytes());
+ }
+ if (i < up.length) {
+ ret[i] = (byte) (sum[i % 16] ^ up[i]);
+ } else {
+ ret[i] = (byte) (sum[i % 16] ^ 0);
+ }
+ md5.update(ret[i]);
+ if ((i % 16) == 15) {
+ sum = md5.digest();
+ }
+ }
+ return ret;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/radius/VendorSpecificAttribute.java b/base/util/src/com/netscape/cmsutil/radius/VendorSpecificAttribute.java
new file mode 100644
index 000000000..5f3d9f170
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/radius/VendorSpecificAttribute.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.radius;
+
+import java.io.IOException;
+
+public class VendorSpecificAttribute extends Attribute {
+ private byte _value[] = null;
+ private String _id = null;
+ private String _str = null;
+
+ public VendorSpecificAttribute(byte value[]) {
+ super();
+ _t = VENDOR_SPECIFIC;
+ _id = new String(value, 2, 4);
+ _str = new String(value, 6, value.length - 6);
+ _value = value;
+ }
+
+ public String getId() {
+ return _id;
+ }
+
+ public String getString() {
+ return _str;
+ }
+
+ public byte[] getValue() throws IOException {
+ byte v[] = new byte[_id.length() + _str.length()];
+ byte idData[] = _id.getBytes();
+ byte strData[] = _str.getBytes();
+
+ System.arraycopy(idData, 0, v, 0, _id.length());
+ System.arraycopy(strData, 0, v, _id.length(), _str.length());
+ return v;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/scep/CRSPKIMessage.java b/base/util/src/com/netscape/cmsutil/scep/CRSPKIMessage.java
new file mode 100644
index 000000000..03bc68723
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/scep/CRSPKIMessage.java
@@ -0,0 +1,905 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.scep;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Hashtable;
+
+import netscape.security.pkcs.PKCS10;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.NULL;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.PrintableString;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.pkcs7.Attribute;
+import org.mozilla.jss.pkcs7.ContentInfo;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
+import org.mozilla.jss.pkcs7.EnvelopedData;
+import org.mozilla.jss.pkcs7.IssuerAndSerialNumber;
+import org.mozilla.jss.pkcs7.RecipientInfo;
+import org.mozilla.jss.pkcs7.SignedData;
+import org.mozilla.jss.pkcs7.SignerInfo;
+import org.mozilla.jss.pkix.cert.Certificate;
+import org.mozilla.jss.pkix.cert.CertificateInfo;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+public class CRSPKIMessage {
+
+ // OIDs for authenticated attributes
+ public static OBJECT_IDENTIFIER CRS_MESSAGETYPE =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 2 }
+ );
+ public static OBJECT_IDENTIFIER CRS_PKISTATUS =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 3 }
+ );
+ public static OBJECT_IDENTIFIER CRS_FAILINFO =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 4 }
+ );
+ public static OBJECT_IDENTIFIER CRS_SENDERNONCE =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 5 }
+ );
+ public static OBJECT_IDENTIFIER CRS_RECIPIENTNONCE =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 6 }
+ );
+ public static OBJECT_IDENTIFIER CRS_TRANSID =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 7 }
+ );
+ public static OBJECT_IDENTIFIER CRS_EXTENSIONREQ =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 113733, 1, 9, 8 }
+ );
+
+ // PKCS9 defined OIDs
+
+ public static OBJECT_IDENTIFIER PKCS9_CONTENT_TYPE =
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 1, 9, 3 }
+ );
+
+ public static OBJECT_IDENTIFIER PKCS9_MESSAGE_DIGEST =
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 1, 9, 4 }
+ );
+
+ /* PKCS 1 - rsaEncryption */
+ public static OBJECT_IDENTIFIER RSA_ENCRYPTION =
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 1, 1, 1 }
+ );
+
+ public static OBJECT_IDENTIFIER DES_CBC_ENCRYPTION =
+ new OBJECT_IDENTIFIER(new long[] { 1, 3, 14, 3, 2, 7 }
+ );
+
+ public static OBJECT_IDENTIFIER DES_EDE3_CBC_ENCRYPTION =
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 3, 7 }
+ );
+
+ public static OBJECT_IDENTIFIER MD5_DIGEST =
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 2, 5 }
+ );
+
+ public static OBJECT_IDENTIFIER SHA1_DIGEST =
+ new OBJECT_IDENTIFIER(new long[] { 1, 3, 14, 3, 2, 26 }
+ );
+
+ public static OBJECT_IDENTIFIER SHA256_DIGEST =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 101, 3, 4, 2, 1 }
+ );
+
+ public static OBJECT_IDENTIFIER SHA512_DIGEST =
+ new OBJECT_IDENTIFIER(new long[] { 2, 16, 840, 1, 101, 3, 4, 2, 3 }
+ );
+
+ // Strings given in 'messageType' authenticated attribute
+ public final static String mType_PKCSReq = "19";
+ public final static String mType_CertRep = "3";
+ public final static String mType_GetCertInitial = "20";
+ public final static String mType_GetCert = "21";
+ public final static String mType_GetCRL = "22";
+
+ // Strings given in 'PKIStatus' authenticated attribute
+ public final static String mStatus_SUCCESS = "0";
+ public final static String mStatus_FAILURE = "2";
+ public final static String mStatus_PENDING = "3";
+
+ // Strings given in 'failInfo' authenticated attribute
+ public final static String mFailInfo_badAlg = "0";
+ public final static String mFailInfo_badMessageCheck = "1";
+ public final static String mFailInfo_badRequest = "2";
+ public final static String mFailInfo_badTime = "3";
+ public final static String mFailInfo_badCertId = "4";
+ public final static String mFailInfo_unsupportedExt = "5";
+ public final static String mFailInfo_mustArchiveKeys = "6";
+ public final static String mFailInfo_badIdentity = "7";
+ public final static String mFailInfo_popRequired = "8";
+ public final static String mFailInfo_popFailed = "9";
+ public final static String mFailInfo_noKeyReuse = "10";
+ public final static String mFailInfo_internalCAError = "11";
+ public final static String mFailInfo_tryLater = "12";
+
+ // ************************************************************************
+ // These private members represent the flattened structure of the PKIMessage
+ // ************************************************************************
+
+ // top level is just a ContentInfo
+ private ContentInfo crsci;
+ // it's content is a signedData
+ private SignedData sd;
+
+ // In the signed data, we have:
+ private int sdv; // Version
+ private ContentInfo data; // The data to be digested
+ private EnvelopedData sded; // Enveloped data inside of signed data
+ private byte[] signerCertBytes;
+ org.mozilla.jss.pkix.cert.Certificate signerCert;
+
+ private SET sis; // set of SignerInfos
+ private SignerInfo si; // First SignerInfo
+ private AlgorithmIdentifier digestAlgorithmId = null;
+ private int siv; // Version
+ private SET aa; // Authenticated Attributes
+ private SET aa_old; // Authenticated Attributes
+ private IssuerAndSerialNumber sgnIASN; // Signer's Issuer Name and Serialnum
+ private OCTET_STRING aa_digest; // digest of the authenticated attrs
+
+ private String messageType; // these are all authenticated attributes
+ private String failInfo;
+ private String pkiStatus;
+ private String transactionID;
+ private byte[] senderNonce;
+ private byte[] recipientNonce;
+ private OCTET_STRING msg_digest; // digest of the message
+
+ // Inside the sded Enveloped data
+ private RecipientInfo ri; // First RecipientInfo
+ private int riv; // Version
+ private AlgorithmIdentifier riAlgid; // alg that the bulk key is wrapped with
+ private byte[] riKey; // bulk key, wrapped with above algorithm
+ private byte[] cKey; // * 'clear', unwrapped key (not in ASN.1) *
+ private IssuerAndSerialNumber rcpIASN; // Recipient's Issuer Name and Serial Number
+
+ private EncryptedContentInfo eci;
+ private byte[] iv; // initialization vector for above key
+ private byte[] ec; // encrypted content (P10, in case of request)
+ private byte[] cc; // * 'clear' content (not in ASN.1) *
+ private String encryptionAlgorithm = null;
+
+ // For the CertRep, the enveloped content is another signed Data:
+ private SignedData crsd;
+ private int rsdVersion;
+ private byte[] rsdCert; // certificate to send in response
+
+ private PKCS10 myP10;
+
+ private Hashtable<String, Object> attrs; // miscellanous
+
+ // *** END *** //
+
+ public void debug() {
+ }
+
+ public void put(String a, Object b) {
+ attrs.put(a, b);
+ }
+
+ public Object get(Object a) {
+ return attrs.get(a);
+ }
+
+ private SignatureAlgorithm getSignatureAlgorithm(String hashAlgorithm) {
+ SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RSASignatureWithMD5Digest;
+ if (hashAlgorithm != null) {
+ if (hashAlgorithm.equals("SHA1")) {
+ signatureAlgorithm = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ } else if (hashAlgorithm.equals("SHA256")) {
+ signatureAlgorithm = SignatureAlgorithm.RSASignatureWithSHA256Digest;
+ } else if (hashAlgorithm.equals("SHA512")) {
+ signatureAlgorithm = SignatureAlgorithm.RSASignatureWithSHA512Digest;
+ }
+ }
+ return signatureAlgorithm;
+ }
+
+ private OBJECT_IDENTIFIER getAlgorithmOID(String hashAlgorithm) {
+ OBJECT_IDENTIFIER oid = MD5_DIGEST;
+ if (hashAlgorithm != null) {
+ if (hashAlgorithm.equals("SHA1")) {
+ oid = SHA1_DIGEST;
+ } else if (hashAlgorithm.equals("SHA256")) {
+ oid = SHA256_DIGEST;
+ } else if (hashAlgorithm.equals("SHA512")) {
+ oid = SHA512_DIGEST;
+ }
+ }
+ return oid;
+ }
+
+ // getHashAlgorithm is added to work around issue 636217
+ private String getHashAlgorithm(OBJECT_IDENTIFIER algorithmOID) {
+ String hashAlgorithm = null;
+ if (algorithmOID != null) {
+ if (algorithmOID.equals(MD5_DIGEST)) {
+ hashAlgorithm = "MD5";
+ } else if (algorithmOID.equals(SHA1_DIGEST)) {
+ hashAlgorithm = "SHA1";
+ } else if (algorithmOID.equals(SHA256_DIGEST)) {
+ hashAlgorithm = "SHA256";
+ } else if (algorithmOID.equals(SHA512_DIGEST)) {
+ hashAlgorithm = "SHA512";
+ }
+ }
+ return hashAlgorithm;
+ }
+
+ // These functions are used to initialize the various blobs
+
+ public void makeSignedData(int version,
+ byte[] certificate, String hashAlgorithm) {
+
+ try {
+ SET digest_algs = new SET();
+
+ digest_algs.addElement(new AlgorithmIdentifier(getAlgorithmOID(hashAlgorithm), new NULL()));
+
+ // SET certs = new SET();
+ // certs.addElement(new ANY(certificate));
+
+ SET sis = new SET();
+
+ sis.addElement(si);
+
+ ContentInfo data = this.data;
+
+ this.sd = new SignedData(
+ digest_algs,
+ data,
+ null, // don't send the certs, he already has them
+ null, // crl's
+ sis);
+
+ } catch (Exception e) {
+ }
+ }
+
+ public byte[] getResponse() throws IOException, InvalidBERException {
+
+ crsci = new ContentInfo(ContentInfo.SIGNED_DATA,
+ sd);
+
+ return ASN1Util.encode(crsci);
+
+ // ANY a = crsci.getContent();
+ // return a.getEncoded();
+ }
+
+ /*
+ public void makeSignerInfo_old(int version,
+ // issuer and serialnumber
+ byte[] digest) {
+
+ si = new SignerInfo(new INTEGER(version),
+ sgnIASN, // issuer and serialnum
+ new AlgorithmIdentifier(MD5_DIGEST, new NULL()), // digest algorithm
+ this.aa, // Authenticated Attributes
+ new AlgorithmIdentifier(RSA_ENCRYPTION,new NULL()), // digest encryption algorithm
+ new OCTET_STRING(digest), // digest
+ null); // unauthenticated attributes
+
+ }
+ */
+
+ public void makeSignerInfo(int version,
+ // issuer and serialnumber
+ org.mozilla.jss.crypto.PrivateKey pk, String hashAlgorithm)
+ throws java.security.NoSuchAlgorithmException,
+ TokenException,
+ java.security.InvalidKeyException,
+ java.security.SignatureException,
+ org.mozilla.jss.CryptoManager.NotInitializedException {
+
+ si = new SignerInfo(sgnIASN, // issuer and serialnum
+ this.aa, // Authenticated Attributes
+ null, // Unauthenticated Attrs
+ ContentInfo.ENVELOPED_DATA, // content type
+ msg_digest.toByteArray(), // digest
+ getSignatureAlgorithm(hashAlgorithm),
+ pk);
+ }
+
+ public void makeAuthenticatedAttributes() {
+
+ aa = new SET();
+
+ try {
+ if (transactionID != null) {
+ SET tidset = new SET();
+
+ tidset.addElement((new PrintableString(transactionID)));
+ aa.addElement(new Attribute(CRS_TRANSID, tidset));
+ }
+
+ if (pkiStatus != null) {
+ SET pkistatusset = new SET();
+
+ pkistatusset.addElement(new PrintableString(pkiStatus));
+ aa.addElement(new Attribute(CRS_PKISTATUS, pkistatusset));
+ }
+
+ if (messageType != null) {
+ SET aaset = new SET();
+
+ aaset.addElement(new PrintableString(messageType));
+ aa.addElement(new Attribute(CRS_MESSAGETYPE, aaset));
+ }
+
+ if (failInfo != null) {
+ SET fiset = new SET();
+
+ fiset.addElement(new PrintableString(failInfo));
+ aa.addElement(new Attribute(CRS_FAILINFO, fiset));
+ }
+
+ if (senderNonce != null) {
+ SET snset = new SET();
+
+ snset.addElement(new OCTET_STRING(senderNonce));
+ aa.addElement(new Attribute(CRS_SENDERNONCE, snset));
+ }
+
+ if (recipientNonce != null) {
+ SET rnset = new SET();
+
+ rnset.addElement(new OCTET_STRING(recipientNonce));
+ aa.addElement(new Attribute(CRS_RECIPIENTNONCE, rnset));
+ }
+
+ // XXX sender nonce
+
+ } catch (CharConversionException e) {
+ }
+ }
+
+ public byte[] makeEnvelopedData(int version) {
+
+ byte[] r;
+
+ try {
+
+ if (this.ri != null) {
+ ContentInfo ci;
+
+ SET ris = new SET();
+
+ ris.addElement(this.ri);
+
+ this.sded = new EnvelopedData(
+ new INTEGER(version),
+ ris,
+ eci);
+
+ ci = new ContentInfo(ContentInfo.ENVELOPED_DATA,
+ sded);
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+
+ ci.encode(ba);
+ r = ba.toByteArray();
+ } else {
+ r = new byte[0];
+ }
+
+ this.data = new ContentInfo(ContentInfo.DATA,
+ new OCTET_STRING(r));
+
+ return r;
+
+ // return this.sded.getEncodedContents();
+ } catch (Exception e) {
+ return null;
+ }
+
+ }
+
+ public void makeRecipientInfo(int version, byte[] riKey) {
+ this.riv = version;
+
+ this.riAlgid = new AlgorithmIdentifier(RSA_ENCRYPTION, new NULL());
+ this.riKey = riKey;
+
+ this.ri = new RecipientInfo(
+ new INTEGER(this.riv),
+ rcpIASN,
+ this.riAlgid,
+ new OCTET_STRING(this.riKey)
+ );
+ }
+
+ public void makeEncryptedContentInfo(byte[] iv, byte[] ec, String algorithm) {
+ this.iv = iv;
+ this.ec = ec;
+
+ try {
+ OBJECT_IDENTIFIER oid = DES_CBC_ENCRYPTION;
+ if (algorithm != null && algorithm.equals("DES3"))
+ oid = DES_EDE3_CBC_ENCRYPTION;
+
+ AlgorithmIdentifier aid = new AlgorithmIdentifier(oid, new OCTET_STRING(iv));
+
+ //eci = EncryptedContentInfo.createCRSCompatibleEncryptedContentInfo(
+ eci = new EncryptedContentInfo(ContentInfo.DATA,
+ aid,
+ new OCTET_STRING(ec)
+ );
+
+ } catch (Exception e) {
+ }
+ }
+
+ public byte[] makeSignedRep(int v, byte[] certificate) {
+ rsdVersion = v;
+ rsdCert = certificate;
+ try {
+ SET certs = new SET();
+ ANY cert = new ANY(certificate);
+
+ certs.addElement(cert);
+
+ crsd = new SignedData(
+ new SET(), // empty set of digestAlgorithmID's
+ new ContentInfo(
+ new OBJECT_IDENTIFIER(new long[] { 1, 2, 840, 113549, 1, 7, 1 }
+ ),
+ null), //empty content
+ certs,
+ null, // no CRL's
+ new SET() // empty SignerInfos
+ );
+ ContentInfo wrap = new ContentInfo(ContentInfo.SIGNED_DATA,
+ crsd);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ wrap.encode(baos);
+
+ return baos.toByteArray();
+ // return crsd.getEncodedContents();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("{ messageType=");
+ sb.append(getMessageType());
+ sb.append(", failInfo=");
+ sb.append(getFailInfo());
+ sb.append(", pkiStatus=");
+ sb.append(getPKIStatus());
+ sb.append(", transactionID=");
+ sb.append(getTransactionID());
+ sb.append(", senderNonce=");
+ sb.append(Arrays.toString(getSenderNonce()));
+ sb.append(", recipientNonce=");
+ sb.append(Arrays.toString(getRecipientNonce()));
+ sb.append(" }");
+
+ String s = sb.toString();
+ return s;
+ }
+
+ public String getMessageType() {
+ return messageType;
+ }
+
+ public String getFailInfo() {
+ return failInfo;
+ }
+
+ public String getPKIStatus() {
+ return pkiStatus;
+ }
+
+ public String getTransactionID() {
+ return transactionID;
+ }
+
+ public byte[] getSenderNonce() {
+ return senderNonce;
+ }
+
+ public byte[] getRecipientNonce() {
+ return recipientNonce;
+ }
+
+ public byte[] getWrappedKey() {
+ return riKey;
+ }
+
+ public byte[] getEncryptedPkcs10() {
+ return ec;
+ }
+
+ public byte[] getIV() {
+ return iv;
+ }
+
+ public String getEncryptionAlgorithm() {
+ return encryptionAlgorithm;
+ }
+
+ public String getDigestAlgorithmName() {
+ String name = null;
+ if (digestAlgorithmId != null) {
+ name = getHashAlgorithm(digestAlgorithmId.getOID());
+ }
+ return name;
+ }
+
+ public PublicKey getSignerPublicKey() {
+ try {
+
+ org.mozilla.jss.pkix.cert.Certificate.Template ct = new
+ org.mozilla.jss.pkix.cert.Certificate.Template();
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(this.signerCertBytes);
+
+ signerCert = (org.mozilla.jss.pkix.cert.Certificate) ct.decode(bais);
+ return signerCert.getInfo().getSubjectPublicKeyInfo().toPublicKey();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public byte[] getAA() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ aa.encode(baos);
+ return baos.toByteArray();
+ } catch (Exception e) {
+ return null;
+ }
+
+ }
+
+ public void setAA_old(SET auth_attrs) {
+ aa_old = auth_attrs;
+ }
+
+ // SWP
+ public byte[] getAA_old() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ aa_old.encode(baos);
+ return baos.toByteArray();
+ } catch (Exception e) {
+ return null;
+ }
+
+ }
+
+ public byte[] getAADigest() {
+ return aa_digest.toByteArray();
+ }
+
+ public PKCS10 getP10() {
+ return myP10;
+ }
+
+ public void setP10(PKCS10 p10) {
+ myP10 = p10;
+ }
+
+ public void setSgnIssuerAndSerialNumber(IssuerAndSerialNumber iasn) {
+ this.sgnIASN = iasn;
+ }
+
+ public void setRcpIssuerAndSerialNumber(IssuerAndSerialNumber iasn) {
+ this.rcpIASN = iasn;
+ }
+
+ public IssuerAndSerialNumber getSgnIssuerAndSerialNumber() {
+ return this.sgnIASN;
+ }
+
+ public IssuerAndSerialNumber getRcpIssuerAndSerialNumber() {
+ return this.rcpIASN;
+ }
+
+ public void setMessageType(String messageType) {
+ this.messageType = messageType;
+ }
+
+ public void setPKIStatus(String pkiStatus) {
+ this.pkiStatus = pkiStatus;
+ }
+
+ public void setFailInfo(String failInfo) {
+ this.failInfo = failInfo;
+ }
+
+ public void setTransactionID(String tid) {
+ this.transactionID = tid;
+ }
+
+ public void setRecipientNonce(byte[] rn) {
+ this.recipientNonce = rn;
+ }
+
+ public void setSenderNonce(byte[] sn) {
+ this.senderNonce = sn;
+ }
+
+ // public void setCertificate(byte [] cert) { this.certificate = cert; }
+
+ public void setMsgDigest(byte[] digest) {
+ this.msg_digest = new OCTET_STRING(digest);
+ }
+
+ public void setAADigest(byte[] digest) {
+ this.aa_digest = new OCTET_STRING(digest);
+ }
+
+ public void setPending() {
+ // setIssuerAndSerialNumber();
+
+ setMessageType(mType_CertRep);
+ setPKIStatus(mStatus_PENDING);
+ };
+
+ public void setFailure(String failInfo) {
+ setMessageType(mType_CertRep);
+ setPKIStatus(mStatus_FAILURE);
+ setFailInfo(failInfo);
+ }
+
+ // Should add a Certificate to this call
+ public void setSuccess() {
+ setMessageType(mType_CertRep);
+ setPKIStatus(mStatus_SUCCESS);
+ }
+
+ /**
+ * Gets a byte array which is the der-encoded blob
+ * which gets sent back to the router.
+ */
+
+ public byte[] getEncoded() {
+ //Assert.assert(messageType != null);
+ //Assert.assert(pkiStatus != null);
+
+ return new byte[1]; // blagh
+ }
+
+ private void decodeCRSPKIMessage(ByteArrayInputStream bais) throws InvalidBERException, Exception {
+
+ org.mozilla.jss.pkcs7.ContentInfo.Template crscit;
+
+ crscit = new ContentInfo.Template();
+ crsci = (ContentInfo) crscit.decode(bais);
+
+ if (!ContentInfo.SIGNED_DATA.equals(crsci.getContentType())) {
+ throw new Exception("ContentType wasn't signed data, it was" + crsci.getContentType());
+ }
+
+ // Now that we know that the contentInfo is a SignedData, we can decode it
+ SignedData.Template sdt = new SignedData.Template();
+
+ sd = (SignedData) sdt.decode(
+ new ByteArrayInputStream(
+ ((ANY) crsci.getContent()).getEncoded()
+ ));
+ this.decodeSD();
+ }
+
+ public CRSPKIMessage() {
+ attrs = new Hashtable<String, Object>();
+ }
+
+ public CRSPKIMessage(ByteArrayInputStream bais) throws InvalidBERException, Exception {
+ attrs = new Hashtable<String, Object>();
+ decodeCRSPKIMessage(bais);
+ }
+
+ private void decodeSD() throws Exception {
+ ContentInfo sdci;
+
+ sis = sd.getSignerInfos();
+
+ decodeSI();
+
+ sdci = sd.getContentInfo();
+
+ // HACK to work with CRS
+ ANY a = (ANY) sdci.getContent();
+ ByteArrayInputStream s = new ByteArrayInputStream(a.getEncoded());
+ OCTET_STRING os = (OCTET_STRING) (new OCTET_STRING.Template()).decode(s);
+
+ ByteArrayInputStream s2 = new ByteArrayInputStream(os.toByteArray());
+ ContentInfo ci = (ContentInfo) (new ContentInfo.Template()).decode(s2);
+ ByteArrayInputStream s3 = new ByteArrayInputStream(((ANY) ci.getContent()).getEncoded());
+
+ EnvelopedData.Template edt = new EnvelopedData.Template();
+
+ sded = (EnvelopedData) edt.decode(s3);
+
+ SET signerCerts = (SET) sd.getCertificates();
+ Certificate firstCert = (Certificate) signerCerts.elementAt(0);
+
+ signerCertBytes = ASN1Util.encode(firstCert);
+
+ CertificateInfo firstCertInfo = firstCert.getInfo();
+
+ sgnIASN = new IssuerAndSerialNumber(firstCertInfo.getIssuer(),
+ firstCertInfo.getSerialNumber());
+
+ decodeED();
+ }
+
+ private void decodeSI() throws Exception {
+ if (sis.size() == 0) {
+ throw new Exception("SignerInfos is empty");
+ }
+ si = (SignerInfo) sis.elementAt(0);
+
+ digestAlgorithmId = si.getDigestAlgorithmIdentifer();
+
+ decodeAA();
+
+ aa_digest = new OCTET_STRING(si.getEncryptedDigest());
+ }
+
+ private void decodeED() throws Exception {
+ SET ris;
+
+ ris = (SET) sded.getRecipientInfos();
+
+ if (ris.size() == 0) {
+ throw new Exception("RecipientInfos is empty");
+ }
+ ri = (RecipientInfo) ris.elementAt(0);
+ eci = sded.getEncryptedContentInfo();
+
+ if (eci.getContentEncryptionAlgorithm().getOID().equals(DES_EDE3_CBC_ENCRYPTION)) {
+ encryptionAlgorithm = "DES3";
+ } else if (eci.getContentEncryptionAlgorithm().getOID().equals(DES_CBC_ENCRYPTION)) {
+ encryptionAlgorithm = "DES";
+ } else {
+ throw new Exception("P10 encrypted alg is not supported (not DES): "
+ + eci.getContentEncryptionAlgorithm().getOID());
+ }
+
+ ec = eci.getEncryptedContent().toByteArray();
+
+ OCTET_STRING.Template ost = new OCTET_STRING.Template();
+
+ OCTET_STRING os = (OCTET_STRING)
+ ost.decode(new ByteArrayInputStream(
+ ((ANY) eci.getContentEncryptionAlgorithm().getParameters()).getEncoded()
+ )
+ );
+
+ iv = os.toByteArray();
+
+ decodeRI();
+ }
+
+ /**
+ * The PKCS10 request is encrypt with a symmetric key.
+ * This key in turn is encrypted with the RSA key in the
+ * CA certificate.
+ *
+ * riAlgid is the algorithm the symm key is encrypted with. It had
+ * better be RSA
+ * riKey is the encrypted symmetric key
+ */
+
+ private void decodeRI() throws Exception {
+
+ // really should get issuer and serial number of our RI, as this
+ // indicates the key we should use to decrypt with. However, we're just
+ // going to assume that the key is the Signing cert for the server.
+
+ riAlgid = ri.getKeyEncryptionAlgorithmID();
+
+ if (!riAlgid.getOID().equals(RSA_ENCRYPTION)) {
+ throw new Exception("Request is protected by a key which we can't decrypt");
+ }
+
+ riKey = ri.getEncryptedKey().toByteArray();
+
+ }
+
+ private void decodeAA() throws InvalidBERException, IOException {
+ aa = si.getAuthenticatedAttributes();
+
+ int count;
+
+ for (count = 0; count < aa.size(); count++) {
+ Attribute a = (Attribute) aa.elementAt(count);
+ SET s = (SET) a.getValues();
+ ANY f = (ANY) s.elementAt(0);
+ PrintableString ps;
+ PrintableString.Template pst = new PrintableString.Template();
+ OCTET_STRING.Template ost = new OCTET_STRING.Template();
+
+ OBJECT_IDENTIFIER oid = a.getType();
+
+ if (oid.equals(CRS_MESSAGETYPE)) {
+ ps = (PrintableString) pst.decode(new ByteArrayInputStream(f.getEncoded()));
+ // We make a new string here
+ messageType = ps.toString();
+
+ } else if (oid.equals(CRS_PKISTATUS)) {
+ ps = (PrintableString) pst.decode(new ByteArrayInputStream(f.getEncoded()));
+ pkiStatus = new String(ps.toString());
+ } else if (oid.equals(CRS_FAILINFO)) {
+ ps = (PrintableString) pst.decode(new ByteArrayInputStream(f.getEncoded()));
+ failInfo = new String(ps.toString());
+ } else if (oid.equals(CRS_SENDERNONCE)) {
+ OCTET_STRING oss = (OCTET_STRING) ost.decode(new ByteArrayInputStream(f.getEncoded()));
+
+ senderNonce = oss.toByteArray();
+ } else if (oid.equals(CRS_RECIPIENTNONCE)) {
+ OCTET_STRING osr = (OCTET_STRING) ost.decode(new ByteArrayInputStream(f.getEncoded()));
+
+ recipientNonce = osr.toByteArray();
+ } else if (oid.equals(CRS_TRANSID)) {
+ ps = (PrintableString) pst.decode(new ByteArrayInputStream(f.getEncoded()));
+ transactionID = new String(ps.toString());
+ }
+
+ }
+
+ } // end of decodeAA();
+
+ public String getMessageTypeString() {
+ if (messageType == null) {
+ return null;
+ }
+
+ if (messageType.equals(mType_PKCSReq)) {
+ return "PKCSReq";
+ }
+ if (messageType.equals(mType_CertRep)) {
+ return "CertRep";
+ }
+ if (messageType.equals(mType_GetCertInitial)) {
+ return "GetCertInitial";
+ }
+ if (messageType.equals(mType_GetCert)) {
+ return "GetCert";
+ }
+ if (messageType.equals(mType_GetCRL)) {
+ return "GetCRL";
+ }
+ // messageType should match one of the above
+ //Assert.assert(false);
+ return null;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/util/Cert.java b/base/util/src/com/netscape/cmsutil/util/Cert.java
new file mode 100644
index 000000000..3563f70c7
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/Cert.java
@@ -0,0 +1,186 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import netscape.security.pkcs.PKCS7;
+import netscape.security.x509.X509CRLImpl;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+
+public class Cert {
+
+ public static SignatureAlgorithm mapAlgorithmToJss(String algname) {
+ if (algname.equals("MD5withRSA"))
+ return SignatureAlgorithm.RSASignatureWithMD5Digest;
+ else if (algname.equals("MD2withRSA"))
+ return SignatureAlgorithm.RSASignatureWithMD2Digest;
+ else if (algname.equals("SHA1withRSA"))
+ return SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ else if (algname.equals("SHA1withDSA"))
+ return SignatureAlgorithm.DSASignatureWithSHA1Digest;
+ else if (algname.equals("SHA256withRSA"))
+ return SignatureAlgorithm.RSASignatureWithSHA256Digest;
+ else if (algname.equals("SHA512withRSA"))
+ return SignatureAlgorithm.RSASignatureWithSHA512Digest;
+ else if (algname.equals("SHA1withEC"))
+ return SignatureAlgorithm.ECSignatureWithSHA1Digest;
+ else if (algname.equals("SHA256withEC"))
+ return SignatureAlgorithm.ECSignatureWithSHA256Digest;
+ else if (algname.equals("SHA384withEC"))
+ return SignatureAlgorithm.ECSignatureWithSHA384Digest;
+ else if (algname.equals("SHA512withEC"))
+ return SignatureAlgorithm.ECSignatureWithSHA512Digest;
+ return null;
+ }
+
+ public static String stripBrackets(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if ((s.startsWith("-----BEGIN CERTIFICATE-----")) &&
+ (s.endsWith("-----END CERTIFICATE-----"))) {
+ return (s.substring(27, (s.length() - 25)));
+ }
+
+ // To support Thawte's header and footer
+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----")) &&
+ (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) {
+ return (s.substring(35, (s.length() - 33)));
+ }
+
+ return s;
+ }
+
+ public static String stripCRLBrackets(String s) {
+ if (s == null) {
+ return s;
+ }
+ if ((s.startsWith("-----BEGIN CERTIFICATE REVOCATION LIST-----")) &&
+ (s.endsWith("-----END CERTIFICATE REVOCATION LIST-----"))) {
+ return (s.substring(43, (s.length() - 41)));
+ }
+ return s;
+ }
+
+ public static String stripCertBrackets(String s) {
+ return stripBrackets(s);
+ }
+
+ // private static BASE64Decoder mDecoder = new BASE64Decoder();
+ public static X509CertImpl mapCert(String mime64)
+ throws IOException {
+ mime64 = stripCertBrackets(mime64.trim());
+ String newval = normalizeCertStr(mime64);
+ // byte rawPub[] = mDecoder.decodeBuffer(newval);
+ byte rawPub[] = Utils.base64decode(newval);
+ X509CertImpl cert = null;
+
+ try {
+ cert = new X509CertImpl(rawPub);
+ } catch (CertificateException e) {
+ }
+ return cert;
+ }
+
+ public static X509Certificate[] mapCertFromPKCS7(String mime64)
+ throws IOException {
+ mime64 = stripCertBrackets(mime64.trim());
+ String newval = normalizeCertStr(mime64);
+ // byte rawPub[] = mDecoder.decodeBuffer(newval);
+ byte rawPub[] = Utils.base64decode(newval);
+ PKCS7 p7 = null;
+
+ try {
+ p7 = new PKCS7(rawPub);
+ } catch (Exception e) {
+ throw new IOException("p7 is null");
+ }
+ return p7.getCertificates();
+ }
+
+ public static X509CRL mapCRL(String mime64)
+ throws IOException {
+ mime64 = stripCRLBrackets(mime64.trim());
+ String newval = normalizeCertStr(mime64);
+ // byte rawPub[] = mDecoder.decodeBuffer(newval);
+ byte rawPub[] = Utils.base64decode(newval);
+ X509CRL crl = null;
+
+ try {
+ crl = new X509CRLImpl(rawPub);
+ } catch (Exception e) {
+ }
+ return crl;
+ }
+
+ public static X509CRL mapCRL1(String mime64)
+ throws IOException {
+ mime64 = stripCRLBrackets(mime64.trim());
+
+ byte rawPub[] = Utils.base64decode(mime64);
+ X509CRL crl = null;
+
+ try {
+ crl = new X509CRLImpl(rawPub);
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ return crl;
+ }
+
+ public static String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\n') {
+ continue;
+ } else if (s.charAt(i) == '\r') {
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ public static String normalizeCertStrAndReq(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\n') {
+ continue;
+ } else if (s.charAt(i) == '\r') {
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/util/Fmt.java b/base/util/src/com/netscape/cmsutil/util/Fmt.java
new file mode 100644
index 000000000..a24b8d090
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/Fmt.java
@@ -0,0 +1,605 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+// Fmt - some simple single-arg sprintf-like routines
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+/// Some simple single-arg sprintf-like routines.
+// <P>
+// It is apparently impossible to declare a Java method that accepts
+// variable numbers of any type of argument. You can declare it to take
+// Objects, but numeric variables and constants are not in fact Objects.
+// <P>
+// However, using the built-in string concatenation, it's almost as
+// convenient to make a series of single-argument formatting routines.
+// <P>
+// Fmt can format the following types:
+// <BLOCKQUOTE><CODE>
+// byte short int long float double char String Object
+// </CODE></BLOCKQUOTE>
+// For each type there is a set of overloaded methods, each returning
+// a formatted String. There's the plain formatting version:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x )
+// </PRE></BLOCKQUOTE>
+// There's a version specifying a minimum field width:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth )
+// </PRE></BLOCKQUOTE>
+// And there's a version that takes flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth, flags )
+// </PRE></BLOCKQUOTE>
+// Currently available flags are:
+// <BLOCKQUOTE><PRE>
+// Fmt.ZF - zero-fill
+// Fmt.LJ - left justify
+// Fmt.HX - hexadecimal
+// Fmt.OC - octal
+// </PRE></BLOCKQUOTE>
+// The HX and OC flags imply unsigned output.
+// <P>
+// For doubles and floats, there's a significant-figures parameter before
+// the flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( d )
+// Fmt.fmt( d, minWidth )
+// Fmt.fmt( d, minWidth, sigFigs )
+// Fmt.fmt( d, minWidth, sigFigs, flags )
+// </PRE></BLOCKQUOTE>
+// <P>
+// <A HREF="/resources/classes/Acme/Fmt.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
+// <HR>
+// Similar classes:
+// <UL>
+// <LI> Andrew Scherpbier's <A HREF="http://www.sdsu.edu/doc/java-SDSU/sdsu.FormatString.html">FormatString</A>
+// Tries to allow variable numbers of arguments by
+// supplying overloaded routines with different combinations of parameters,
+// but doesn't actually supply that many. The floating point conversion
+// is described as "very incomplete".
+// <LI> Core Java's <A HREF="http://www.apl.jhu.edu/~hall/java/CoreJava-Format.html">Format</A>.
+// The design seems a little weird. They want you to create an instance,
+// passing the format string to the constructor, and then call an instance
+// method with your data to do the actual formatting. The extra steps are
+// pointless; better to just use static methods.
+// </UL>
+
+public class Fmt {
+
+ // Flags.
+ /// Zero-fill.
+ public static final int ZF = 1;
+ /// Left justify.
+ public static final int LJ = 2;
+ /// Hexadecimal.
+ public static final int HX = 4;
+ /// Octal.
+ public static final int OC = 8;
+ // Was a number - internal use.
+ private static final int WN = 16;
+
+ // byte
+ public static String fmt(byte b) {
+ return fmt(b, 0, 0);
+ }
+
+ public static String fmt(byte b, int minWidth) {
+ return fmt(b, minWidth, 0);
+ }
+
+ public static String fmt(byte b, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(Integer.toString(b & 0xff, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(Integer.toString(b & 0xff, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(b & 0xff), minWidth, flags | WN);
+ }
+
+ // short
+ public static String fmt(short s) {
+ return fmt(s, 0, 0);
+ }
+
+ public static String fmt(short s, int minWidth) {
+ return fmt(s, minWidth, 0);
+ }
+
+ public static String fmt(short s, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(
+ Integer.toString(s & 0xffff, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(
+ Integer.toString(s & 0xffff, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(s), minWidth, flags | WN);
+ }
+
+ // int
+ public static String fmt(int i) {
+ return fmt(i, 0, 0);
+ }
+
+ public static String fmt(int i, int minWidth) {
+ return fmt(i, minWidth, 0);
+ }
+
+ public static String fmt(int i, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(
+ Long.toString(i & 0xffffffffL, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(
+ Long.toString(i & 0xffffffffL, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(i), minWidth, flags | WN);
+ }
+
+ // long
+ public static String fmt(long l) {
+ return fmt(l, 0, 0);
+ }
+
+ public static String fmt(long l, int minWidth) {
+ return fmt(l, minWidth, 0);
+ }
+
+ public static String fmt(long l, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal) {
+ if ((l & 0xf000000000000000L) != 0)
+ return fmt(
+ Long.toString(l >>> 60, 16) +
+ fmt(l & 0x0fffffffffffffffL, 15, HX | ZF),
+ minWidth, flags | WN);
+ else
+ return fmt(Long.toString(l, 16), minWidth, flags | WN);
+ } else if (octal) {
+ if ((l & 0x8000000000000000L) != 0)
+ return fmt(
+ Long.toString(l >>> 63, 8) +
+ fmt(l & 0x7fffffffffffffffL, 21, OC | ZF),
+ minWidth, flags | WN);
+ else
+ return fmt(Long.toString(l, 8), minWidth, flags | WN);
+ } else
+ return fmt(Long.toString(l), minWidth, flags | WN);
+ }
+
+ // float
+ public static String fmt(float f) {
+ return fmt(f, 0, 0, 0);
+ }
+
+ public static String fmt(float f, int minWidth) {
+ return fmt(f, minWidth, 0, 0);
+ }
+
+ public static String fmt(float f, int minWidth, int sigFigs) {
+ return fmt(f, minWidth, sigFigs, 0);
+ }
+
+ public static String fmt(float f, int minWidth, int sigFigs, int flags) {
+ if (sigFigs != 0)
+ return fmt(
+ sigFigFix(Float.toString(f), sigFigs), minWidth,
+ flags | WN);
+ else
+ return fmt(Float.toString(f), minWidth, flags | WN);
+ }
+
+ // double
+ public static String fmt(double d) {
+ return fmt(d, 0, 0, 0);
+ }
+
+ public static String fmt(double d, int minWidth) {
+ return fmt(d, minWidth, 0, 0);
+ }
+
+ public static String fmt(double d, int minWidth, int sigFigs) {
+ return fmt(d, minWidth, sigFigs, 0);
+ }
+
+ public static String fmt(double d, int minWidth, int sigFigs, int flags) {
+ if (sigFigs != 0)
+ return fmt(
+ sigFigFix(doubleToString(d), sigFigs), minWidth,
+ flags | WN);
+ else
+ return fmt(doubleToString(d), minWidth, flags | WN);
+ }
+
+ // char
+ public static String fmt(char c) {
+ return fmt(c, 0, 0);
+ }
+
+ public static String fmt(char c, int minWidth) {
+ return fmt(c, minWidth, 0);
+ }
+
+ public static String fmt(char c, int minWidth, int flags) {
+ // return fmt( Character.toString( c ), minWidth, flags );
+ // Character currently lacks a static toString method. Workaround
+ // is to make a temporary instance and use the instance toString.
+ return fmt(Character.valueOf(c).toString(), minWidth, flags);
+ }
+
+ // Object
+ public static String fmt(Object o) {
+ return fmt(o, 0, 0);
+ }
+
+ public static String fmt(Object o, int minWidth) {
+ return fmt(o, minWidth, 0);
+ }
+
+ public static String fmt(Object o, int minWidth, int flags) {
+ return fmt(o.toString(), minWidth, flags);
+ }
+
+ // String
+ public static String fmt(String s) {
+ return fmt(s, 0, 0);
+ }
+
+ public static String fmt(String s, int minWidth) {
+ return fmt(s, minWidth, 0);
+ }
+
+ public static String fmt(String s, int minWidth, int flags) {
+ int len = s.length();
+ boolean zeroFill = ((flags & ZF) != 0);
+ boolean leftJustify = ((flags & LJ) != 0);
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+ boolean wasNumber = ((flags & WN) != 0);
+
+ if ((hexadecimal || octal || zeroFill) && !wasNumber)
+ throw new InternalError("Acme.Fmt: number flag on a non-number");
+ if (zeroFill && leftJustify)
+ throw new InternalError("Acme.Fmt: zero-fill left-justify is silly");
+ if (hexadecimal && octal)
+ throw new InternalError("Acme.Fmt: can't do both hex and octal");
+ if (len >= minWidth)
+ return s;
+ int fillWidth = minWidth - len;
+ StringBuffer fill = new StringBuffer(fillWidth);
+
+ for (int i = 0; i < fillWidth; ++i)
+ if (zeroFill)
+ fill.append('0');
+ else
+ fill.append(' ');
+ if (leftJustify)
+ return s + fill;
+ else if (zeroFill && s.startsWith("-"))
+ return "-" + fill + s.substring(1);
+ else
+ return fill + s;
+ }
+
+ // Internal routines.
+
+ private static String sigFigFix(String s, int sigFigs) {
+ // First dissect the floating-point number string into sign,
+ // integer part, fraction part, and exponent.
+ String sign;
+ String unsigned;
+
+ if (s.startsWith("-") || s.startsWith("+")) {
+ sign = s.substring(0, 1);
+ unsigned = s.substring(1);
+ } else {
+ sign = "";
+ unsigned = s;
+ }
+ String mantissa;
+ String exponent;
+ int eInd = unsigned.indexOf('e');
+
+ if (eInd == -1) {
+ mantissa = unsigned;
+ exponent = "";
+ } else {
+ mantissa = unsigned.substring(0, eInd);
+ exponent = unsigned.substring(eInd);
+ }
+ StringBuffer number, fraction;
+ int dotInd = mantissa.indexOf('.');
+
+ if (dotInd == -1) {
+ number = new StringBuffer(mantissa);
+ fraction = new StringBuffer("");
+ } else {
+ number = new StringBuffer(mantissa.substring(0, dotInd));
+ fraction = new StringBuffer(mantissa.substring(dotInd + 1));
+ }
+
+ int numFigs = number.length();
+ int fracFigs = fraction.length();
+
+ if ((numFigs == 0 || number.toString().equals("0")) &&
+ fracFigs > 0) {
+ // Don't count leading zeros in the fraction.
+ numFigs = 0;
+ for (int i = 0; i < fraction.length(); ++i) {
+ if (fraction.charAt(i) != '0')
+ break;
+ --fracFigs;
+ }
+ }
+ int mantFigs = numFigs + fracFigs;
+
+ if (sigFigs > mantFigs) {
+ // We want more figures; just append zeros to the fraction.
+ for (int i = mantFigs; i < sigFigs; ++i)
+ fraction.append('0');
+ } else if (sigFigs < mantFigs && sigFigs >= numFigs) {
+ // Want fewer figures in the fraction; chop.
+ fraction.setLength(
+ fraction.length() - (fracFigs - (sigFigs - numFigs)));
+ // Round?
+ } else if (sigFigs < numFigs) {
+ // Want fewer figures in the number; turn them to zeros.
+ fraction.setLength(0); // should already be zero, but make sure
+ for (int i = sigFigs; i < numFigs; ++i)
+ number.setCharAt(i, '0');
+ // Round?
+ }
+ // Else sigFigs == mantFigs, which is fine.
+
+ if (fraction.length() == 0)
+ return sign + number + exponent;
+ else
+ return sign + number + "." + fraction + exponent;
+ }
+
+ /// Improved version of Double.toString(), returns more decimal places.
+ // <P>
+ // The JDK 1.0.2 version of Double.toString() returns only six decimal
+ // places on some systems. In JDK 1.1 full precision is returned on
+ // all platforms.
+ // @deprecated
+ // @see java.lang.Double.toString
+ public static String doubleToString(double d) {
+ // Handle special numbers first, to avoid complications.
+ if (Double.isNaN(d))
+ return "NaN";
+ if (d == Double.NEGATIVE_INFINITY)
+ return "-Inf";
+ if (d == Double.POSITIVE_INFINITY)
+ return "Inf";
+
+ // Grab the sign, and then make the number positive for simplicity.
+ boolean negative = false;
+
+ if (d < 0.0D) {
+ negative = true;
+ d = -d;
+ }
+
+ // Get the native version of the unsigned value, as a template.
+ String unsStr = Double.toString(d);
+
+ // Dissect out the exponent.
+ String mantStr, expStr;
+ int exp;
+ int eInd = unsStr.indexOf('e');
+
+ if (eInd == -1) {
+ mantStr = unsStr;
+ expStr = "";
+ exp = 0;
+ } else {
+ mantStr = unsStr.substring(0, eInd);
+ expStr = unsStr.substring(eInd + 1);
+ if (expStr.startsWith("+"))
+ exp = Integer.parseInt(expStr.substring(1));
+ else
+ exp = Integer.parseInt(expStr);
+ }
+
+ // Dissect out the number part.
+ String numStr;
+ int dotInd = mantStr.indexOf('.');
+
+ if (dotInd == -1)
+ numStr = mantStr;
+ else
+ numStr = mantStr.substring(0, dotInd);
+ long num;
+
+ if (numStr.length() == 0)
+ num = 0;
+ else
+ num = Integer.parseInt(numStr);
+
+ // Build the new mantissa.
+ StringBuffer newMantBuf = new StringBuffer(numStr + ".");
+ double p = Math.pow(10, exp);
+ double frac = d - num * p;
+ String digits = "0123456789";
+ int nDigits = 16 - numStr.length(); // about 16 digits in a double
+
+ for (int i = 0; i < nDigits; ++i) {
+ p /= 10.0D;
+ int dig = (int) (frac / p);
+
+ if (dig < 0)
+ dig = 0;
+ if (dig > 9)
+ dig = 9;
+ newMantBuf.append(digits.charAt(dig));
+ frac -= dig * p;
+ }
+
+ if ((int) (frac / p + 0.5D) == 1) {
+ // Round up.
+ boolean roundMore = true;
+
+ for (int i = newMantBuf.length() - 1; i >= 0; --i) {
+ int dig = digits.indexOf(newMantBuf.charAt(i));
+
+ if (dig == -1)
+ continue;
+ ++dig;
+ if (dig == 10) {
+ newMantBuf.setCharAt(i, '0');
+ continue;
+ }
+ newMantBuf.setCharAt(i, digits.charAt(dig));
+ roundMore = false;
+ break;
+ }
+ if (roundMore) {
+ // If this happens, we need to prepend a 1. But I haven't
+ // found a test case yet, so I'm leaving it out for now.
+ // But if you get this message, please let me know!
+ newMantBuf.append("ROUNDMORE");
+ }
+ }
+
+ // Chop any trailing zeros.
+ int len = newMantBuf.length();
+
+ while (newMantBuf.charAt(len - 1) == '0')
+ newMantBuf.setLength(--len);
+ // And chop a trailing dot, if any.
+ if (newMantBuf.charAt(len - 1) == '.')
+ newMantBuf.setLength(--len);
+
+ // Done.
+ return (negative ? "-" : "") +
+ newMantBuf +
+ (expStr.length() != 0 ? ("e" + expStr) : "");
+ }
+
+ /******************************************************************************
+ * /// Test program.
+ * public static void main( String[] args )
+ * {
+ * System.out.println( "Starting tests." );
+ * show( Fmt.fmt( "Hello there." ) );
+ * show( Fmt.fmt( 123 ) );
+ * show( Fmt.fmt( 123, 10 ) );
+ * show( Fmt.fmt( 123, 10, Fmt.ZF ) );
+ * show( Fmt.fmt( 123, 10, Fmt.LJ ) );
+ * show( Fmt.fmt( -123 ) );
+ * show( Fmt.fmt( -123, 10 ) );
+ * show( Fmt.fmt( -123, 10, Fmt.ZF ) );
+ * show( Fmt.fmt( -123, 10, Fmt.LJ ) );
+ * show( Fmt.fmt( (byte) 0xbe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( (short) 0xbabe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0xcafebabe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0xdeadbeefcafebabeL, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0x8000000000000000L, 22, Fmt.OC ) );
+ * show( Fmt.fmt( (byte) 0xbe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( (short) 0xbabe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0xcafebabe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0xdeadbeefcafebabeL, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0x8000000000000000L, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 'c' ) );
+ * show( Fmt.fmt( new java.util.Date() ) );
+ * show( Fmt.fmt( 123.456F ) );
+ * show( Fmt.fmt( 123456000000000000.0F ) );
+ * show( Fmt.fmt( 123.456F, 0, 8 ) );
+ * show( Fmt.fmt( 123.456F, 0, 7 ) );
+ * show( Fmt.fmt( 123.456F, 0, 6 ) );
+ * show( Fmt.fmt( 123.456F, 0, 5 ) );
+ * show( Fmt.fmt( 123.456F, 0, 4 ) );
+ * show( Fmt.fmt( 123.456F, 0, 3 ) );
+ * show( Fmt.fmt( 123.456F, 0, 2 ) );
+ * show( Fmt.fmt( 123.456F, 0, 1 ) );
+ * show( Fmt.fmt( 123456000000000000.0F, 0, 4 ) );
+ * show( Fmt.fmt( -123.456F, 0, 4 ) );
+ * show( Fmt.fmt( -123456000000000000.0F, 0, 4 ) );
+ * show( Fmt.fmt( 123.0F ) );
+ * show( Fmt.fmt( 123.0D ) );
+ * show( Fmt.fmt( 1.234567890123456789F ) );
+ * show( Fmt.fmt( 1.234567890123456789D ) );
+ * show( Fmt.fmt( 1234567890123456789F ) );
+ * show( Fmt.fmt( 1234567890123456789D ) );
+ * show( Fmt.fmt( 0.000000000000000000001234567890123456789F ) );
+ * show( Fmt.fmt( 0.000000000000000000001234567890123456789D ) );
+ * show( Fmt.fmt( 12300.0F ) );
+ * show( Fmt.fmt( 12300.0D ) );
+ * show( Fmt.fmt( 123000.0F ) );
+ * show( Fmt.fmt( 123000.0D ) );
+ * show( Fmt.fmt( 1230000.0F ) );
+ * show( Fmt.fmt( 1230000.0D ) );
+ * show( Fmt.fmt( 12300000.0F ) );
+ * show( Fmt.fmt( 12300000.0D ) );
+ * show( Fmt.fmt( Float.NaN ) );
+ * show( Fmt.fmt( Float.POSITIVE_INFINITY ) );
+ * show( Fmt.fmt( Float.NEGATIVE_INFINITY ) );
+ * show( Fmt.fmt( Double.NaN ) );
+ * show( Fmt.fmt( Double.POSITIVE_INFINITY ) );
+ * show( Fmt.fmt( Double.NEGATIVE_INFINITY ) );
+ * show( Fmt.fmt( 1.0F / 8.0F ) );
+ * show( Fmt.fmt( 1.0D / 8.0D ) );
+ * System.out.println( "Done with tests." );
+ * }
+ *
+ * private static void show( String str )
+ * {
+ * System.out.println( "#" + str + "#" );
+ * }
+ ******************************************************************************/
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/util/HMACDigest.java b/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
new file mode 100644
index 000000000..09bf53bbf
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
@@ -0,0 +1,198 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+import java.security.MessageDigest;
+
+/**
+ * This class implements the HMAC algorithm specified in RFC 2104 using
+ * any MessageDigest.
+ *
+ * @author mikep
+ * @version $Revision$, $Date$
+ * @see java.security.MessageDigest
+ */
+public class HMACDigest implements Cloneable {
+ public static final int PAD_BYTES = 64;
+ public static final int IPAD = 0x36;
+ public static final int OPAD = 0x5C;
+
+ /**
+ * inner padding - key XORd with ipad
+ */
+ private byte[] mKeyIpad = new byte[PAD_BYTES];
+
+ /**
+ * outer padding - key XORd with opad
+ */
+ private byte[] mKeyOpad = new byte[PAD_BYTES];
+
+ /**
+ * The real MessageDigest
+ */
+ private MessageDigest mMD = null;
+
+ /**
+ * Creates an HMACDigest
+ *
+ * @param md The MessageDigest to be used for the HMAC calculation. It
+ * must be clonable.
+ */
+ public HMACDigest(MessageDigest md) {
+ mMD = md;
+ }
+
+ /**
+ * Creates an HMACDigest and initializes the HMAC function
+ * with the given key.
+ *
+ * @param md The MessageDigest to be used for the HMAC calculation. It
+ * must be clonable.
+ * @param key The key value to be used in the HMAC calculation
+ */
+ public HMACDigest(MessageDigest md, byte[] key) {
+ this(md);
+ init(key);
+ }
+
+ /**
+ * Return the MessageDigest used for this HMAC
+ */
+ public MessageDigest getMessageDigest() {
+ return mMD;
+ }
+
+ /**
+ * Initialize the HMAC function
+ *
+ * The HMAC transform looks like:
+ *
+ * hash(key XOR opad, hash(key XOR ipad, text))
+ *
+ * where key is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ *
+ * This routine must be called after every reset.
+ *
+ * @param key The password used to protect the hash value
+ */
+ public void init(byte[] key) {
+ int i;
+
+ reset();
+
+ // If the key is longer than 64 bytes, just hash it down
+ if (key.length > 64) {
+ key = mMD.digest(key);
+ mMD.reset(); // Redundant?
+ }
+
+ // Copy the key. Truncate if key is too long
+ for (i = 0; i < key.length && i < PAD_BYTES; i++) {
+ mKeyIpad[i] = key[i];
+ mKeyOpad[i] = key[i];
+ }
+
+ // XOR in the pads
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] ^= IPAD;
+ mKeyOpad[i] ^= OPAD;
+ }
+
+ mMD.update(mKeyIpad);
+
+ // Hmmm, we really shouldn't key Opad around in memory for so
+ // long, but it would just force the user to key their key around
+ // until digest() time. Oh well, at least clear the key and Ipad
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] = 0;
+ }
+ for (i = 0; i < key.length; i++) {
+ key[0] = 0;
+ }
+ }
+
+ /**
+ * Updates the digest using the specified array of bytes.
+ *
+ * @param input the array of bytes.
+ */
+ public void update(byte[] input) {
+ mMD.update(input);
+ }
+
+ /**
+ * Completes the HMAC computation with the outer pad
+ * The digest is reset after this call is made.
+ *
+ * @return the array of bytes for the resulting hash value.
+ */
+ public byte[] digest() {
+ byte[] finalDigest;
+ byte[] innerDigest = mMD.digest();
+
+ mMD.reset(); // Redundant?
+ mMD.update(mKeyOpad);
+ mMD.update(innerDigest);
+ finalDigest = mMD.digest();
+ reset(); // Clear pad arrays
+ return finalDigest;
+ }
+
+ /**
+ * Resets the digest for further use.
+ */
+ public void reset() {
+ int i;
+
+ mMD.reset();
+
+ // Clear out the pads
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] = 0;
+ mKeyOpad[i] = 0;
+ }
+ }
+
+ /**
+ * Clone the HMACDigest
+ *
+ * @return a clone if the implementation is cloneable.
+ * @exception CloneNotSupportedException if this is called on a
+ * MessageDigest implementation that does not support <code>Cloneable</code>.
+ */
+ public Object clone() throws CloneNotSupportedException {
+ int i;
+
+ HMACDigest hd = (HMACDigest) super.clone();
+
+ hd.mKeyOpad = new byte[PAD_BYTES];
+ hd.mKeyIpad = new byte[PAD_BYTES];
+
+ for (i = 0; i < PAD_BYTES; i++) {
+ hd.mKeyOpad[i] = mKeyOpad[i];
+ hd.mKeyIpad[i] = mKeyIpad[i];
+ }
+
+ hd.mMD = (MessageDigest) mMD.clone();
+ return hd;
+ }
+
+}
diff --git a/base/util/src/com/netscape/cmsutil/util/Utils.java b/base/util/src/com/netscape/cmsutil/util/Utils.java
new file mode 100644
index 000000000..303566416
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/Utils.java
@@ -0,0 +1,276 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Vector;
+
+public class Utils {
+ /**
+ * Checks if this is NT.
+ */
+ public static boolean isNT() {
+ return File.separator.equals("\\");
+ }
+
+ public static boolean isUnix() {
+ return File.separator.equals("/");
+ }
+
+ public static boolean exec(String cmd) {
+ try {
+ String cmds[] = null;
+ if (isNT()) {
+ // NT
+ cmds = new String[3];
+ cmds[0] = "cmd";
+ cmds[1] = "/c";
+ cmds[2] = cmd;
+ } else {
+ // UNIX
+ cmds = new String[3];
+ cmds[0] = "/bin/sh";
+ cmds[1] = "-c";
+ cmds[2] = cmd;
+ }
+ Process process = Runtime.getRuntime().exec(cmds);
+ process.waitFor();
+
+ if (process.exitValue() == 0) {
+ /**
+ * pOut = new BufferedReader(
+ * new InputStreamReader(process.getInputStream()));
+ * while ((l = pOut.readLine()) != null) {
+ * System.out.println(l);
+ * }
+ **/
+ return true;
+ } else {
+ /**
+ * pOut = new BufferedReader(
+ * new InputStreamReader(process.getErrorStream()));
+ * l = null;
+ * while ((l = pOut.readLine()) != null) {
+ * System.out.println(l);
+ * }
+ **/
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public static String SpecialURLDecode(String s) {
+ if (s == null)
+ return null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length());
+
+ for (int i = 0; i < s.length(); i++) {
+ int c = (int) s.charAt(i);
+
+ if (c == '+') {
+ out.write(' ');
+ } else if (c == '#') {
+ int c1 = Character.digit(s.charAt(++i), 16);
+ int c2 = Character.digit(s.charAt(++i), 16);
+
+ out.write((char) (c1 * 16 + c2));
+ } else {
+ out.write(c);
+ }
+ } // end for
+ return out.toString();
+ }
+
+ public static byte[] SpecialDecode(String s) {
+ if (s == null)
+ return null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length());
+
+ for (int i = 0; i < s.length(); i++) {
+ int c = (int) s.charAt(i);
+
+ if (c == '+') {
+ out.write(' ');
+ } else if (c == '#') {
+ int c1 = Character.digit(s.charAt(++i), 16);
+ int c2 = Character.digit(s.charAt(++i), 16);
+
+ out.write((char) (c1 * 16 + c2));
+ } else {
+ out.write(c);
+ }
+ } // end for
+ return out.toByteArray();
+ }
+
+ public static String SpecialEncode(byte data[]) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ sb.append("%");
+ if ((data[i] & 0xff) < 16) {
+ sb.append("0");
+ }
+ sb.append(Integer.toHexString((data[i] & 0xff)));
+ }
+ return sb.toString().toUpperCase();
+ }
+
+ public static void checkHost(String hostname) throws UnknownHostException {
+ InetAddress.getByName(hostname);
+ }
+
+ public static void copy(String orig, String dest) {
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(orig));
+ PrintWriter out = new PrintWriter(
+ new BufferedWriter(new FileWriter(dest)));
+ String line = "";
+ while (in.ready()) {
+ line = in.readLine();
+ if (line != null)
+ out.println(line);
+ }
+ in.close();
+ out.close();
+ } catch (Exception ee) {
+ }
+ }
+
+ public static void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] buf = new byte[4096];
+ int len;
+
+ while ((len = in.read(buf)) != -1) {
+ out.write(buf, 0, len);
+ }
+ }
+
+ public static void copyStream(BufferedReader in, OutputStreamWriter out) throws IOException {
+ char[] buf = new char[4096];
+ int len;
+
+ while ((len = in.read(buf)) != -1) {
+ out.write(buf, 0, len);
+ }
+ }
+
+ /// Sorts an array of Strings.
+ // Java currently has no general sort function. Sorting Strings is
+ // common enough that it's worth making a special case.
+ public static void sortStrings(String[] strings) {
+ // Just does a bubblesort.
+ for (int i = 0; i < strings.length - 1; ++i) {
+ for (int j = i + 1; j < strings.length; ++j) {
+ if (strings[i].compareTo(strings[j]) > 0) {
+ String t = strings[i];
+
+ strings[i] = strings[j];
+ strings[j] = t;
+ }
+ }
+ }
+ }
+
+ /// Returns a date string formatted in Unix ls style - if it's within
+ // six months of now, Mmm dd hh:ss, else Mmm dd yyyy.
+ public static String lsDateStr(Date date) {
+ long dateTime = date.getTime();
+
+ if (dateTime == -1L)
+ return "------------";
+ long nowTime = System.currentTimeMillis();
+ SimpleDateFormat formatter = new SimpleDateFormat();
+
+ if (Math.abs(nowTime - dateTime) < 183L * 24L * 60L * 60L * 1000L)
+ formatter.applyPattern("MMM dd hh:ss");
+ else
+ formatter.applyPattern("MMM dd yyyy");
+ return formatter.format(date);
+ }
+
+ /**
+ * compares contents two byte arrays returning true if exactly same.
+ */
+ static public boolean byteArraysAreEqual(byte[] a, byte[] b) {
+ if (a.length != b.length)
+ return false;
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * strips out double quotes around String parameter
+ *
+ * @param s the string potentially bracketed with double quotes
+ * @return string stripped of surrounding double quotes
+ */
+ public static String stripQuotes(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if ((s.startsWith("\"")) && (s.endsWith("\""))) {
+ return (s.substring(1, (s.length() - 1)));
+ }
+
+ return s;
+ }
+
+ /**
+ * returns an array of strings from a vector of Strings
+ * there'll be trouble if the Vector contains something other
+ * than just Strings
+ */
+ public static String[] getStringArrayFromVector(Vector<String> v) {
+ String s[] = new String[v.size()];
+
+ v.copyInto(s);
+ return s;
+ }
+
+ public static String base64encode(byte[] bytes) {
+ String string = new Base64(64).encodeToString(bytes);
+ return string;
+ }
+
+ public static byte[] base64decode(String string) {
+ byte[] bytes = Base64.decodeBase64(string);
+ return bytes;
+ }
+}
diff --git a/base/util/src/com/netscape/cmsutil/xml/XMLObject.java b/base/util/src/com/netscape/cmsutil/xml/XMLObject.java
new file mode 100644
index 000000000..ed2fb67ee
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/xml/XMLObject.java
@@ -0,0 +1,187 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.xml;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+
+public class XMLObject {
+ private Document mDoc = null;
+
+ public XMLObject() throws ParserConfigurationException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = factory.newDocumentBuilder();
+ mDoc = docBuilder.newDocument();
+ }
+
+ public XMLObject(InputStream s)
+ throws SAXException, IOException, ParserConfigurationException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = factory.newDocumentBuilder();
+ mDoc = docBuilder.parse(s);
+ }
+
+ public XMLObject(File f)
+ throws SAXException, IOException, ParserConfigurationException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = factory.newDocumentBuilder();
+ mDoc = docBuilder.parse(f);
+ }
+
+ public Document getDocument() {
+ return mDoc;
+ }
+
+ /**
+ * Each document should have 1 root only. This method should be called once.
+ */
+ public Node createRoot(String name) {
+ Element root = mDoc.createElement(name);
+ mDoc.appendChild(root);
+ return (Node) root;
+ }
+
+ public Node getRoot() {
+ return mDoc.getFirstChild();
+ }
+
+ /**
+ * If you have duplicate containers, then this method will return the
+ * first container in the list.
+ */
+ public Node getContainer(String tagname) {
+ NodeList list = mDoc.getElementsByTagName(tagname);
+ if (list.getLength() > 0)
+ return list.item(0);
+ return null;
+ }
+
+ public Node createContainer(Node containerParent, String containerName) {
+ Element node = mDoc.createElement(containerName);
+ containerParent.appendChild(node);
+ return (Node) node;
+ }
+
+ public void addItemToContainer(Node container, String tagname, String value) {
+ Element node = mDoc.createElement(tagname);
+ Text text = mDoc.createTextNode(value);
+ node.appendChild(text);
+ container.appendChild(node);
+ }
+
+ public String getValue(String tagname) {
+ Node n = getContainer(tagname);
+
+ if (n != null) {
+ NodeList c = n.getChildNodes();
+ if (c.getLength() == 0)
+ return null;
+ Node item = c.item(0);
+ return item.getNodeValue();
+ }
+
+ return null;
+ }
+
+ public Vector<String> getAllValues(String tagname) {
+ Vector<String> v = new Vector<String>();
+ NodeList nodes = mDoc.getElementsByTagName(tagname);
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node n = nodes.item(i);
+ NodeList c = n.getChildNodes();
+ if (c.getLength() > 0) {
+ Node nn = c.item(0);
+ if (nn.getNodeType() == Node.TEXT_NODE)
+ v.addElement(nn.getNodeValue());
+ }
+ }
+ return v;
+ }
+
+ public Vector<String> getValuesFromContainer(Node container, String tagname) {
+ Vector<String> v = new Vector<String>();
+ NodeList c = container.getChildNodes();
+ int len = c.getLength();
+ for (int i = 0; i < len; i++) {
+ Node subchild = c.item(i);
+ if (subchild.getNodeName().equals(tagname)) {
+ NodeList grandchildren = subchild.getChildNodes();
+ if (grandchildren.getLength() > 0) {
+ Node grandchild = grandchildren.item(0);
+ if (grandchild.getNodeType() == Node.TEXT_NODE)
+ v.addElement(grandchild.getNodeValue());
+ }
+ }
+ }
+
+ return v;
+ }
+
+ public byte[] toByteArray() throws TransformerConfigurationException, TransformerException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TransformerFactory tranFactory = TransformerFactory.newInstance();
+ Transformer aTransformer = tranFactory.newTransformer();
+ Source src = new DOMSource(mDoc);
+ Result dest = new StreamResult(bos);
+ aTransformer.transform(src, dest);
+ return bos.toByteArray();
+ }
+
+ public void output(OutputStream os)
+ throws TransformerConfigurationException, TransformerException {
+ TransformerFactory tranFactory = TransformerFactory.newInstance();
+ Transformer aTransformer = tranFactory.newTransformer();
+ Source src = new DOMSource(mDoc);
+ Result dest = new StreamResult(os);
+ aTransformer.transform(src, dest);
+ }
+
+ public String toXMLString() throws TransformerConfigurationException, TransformerException {
+ TransformerFactory tranFactory = TransformerFactory.newInstance();
+ Transformer transformer = tranFactory.newTransformer();
+ Source src = new DOMSource(mDoc);
+ StreamResult dest = new StreamResult(new StringWriter());
+ transformer.transform(src, dest);
+ String xmlString = dest.getWriter().toString();
+ return xmlString;
+ }
+}
diff --git a/base/util/src/netscape/net/NetworkClient.java b/base/util/src/netscape/net/NetworkClient.java
new file mode 100644
index 000000000..ae8cdfcf4
--- /dev/null
+++ b/base/util/src/netscape/net/NetworkClient.java
@@ -0,0 +1,87 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.net;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * This is the base class for network clients.
+ *
+ * @version 1.21, 08/07/97
+ * @author Jonathan Payne
+ */
+public class NetworkClient {
+ /** Socket for communicating with server. */
+ protected Socket serverSocket = null;
+
+ /** Stream for printing to the server. */
+ public PrintStream serverOutput;
+
+ /** Buffered stream for reading replies from server. */
+ public InputStream serverInput;
+
+ /** Open a connection to the server. */
+ public void openServer(String server, int port)
+ throws IOException, UnknownHostException {
+ if (serverSocket != null)
+ closeServer();
+ serverSocket = doConnect(server, port);
+ serverOutput = new PrintStream(new BufferedOutputStream(serverSocket.getOutputStream()),
+ true);
+ serverInput = new BufferedInputStream(serverSocket.getInputStream());
+ }
+
+ /**
+ * Return a socket connected to the server, with any
+ * appropriate options pre-established
+ */
+ protected Socket doConnect(String server, int port)
+ throws IOException, UnknownHostException {
+ return new Socket(server, port);
+ }
+
+ /** Close an open connection to the server. */
+ public void closeServer() throws IOException {
+ if (!serverIsOpen()) {
+ return;
+ }
+ serverSocket.close();
+ serverSocket = null;
+ serverInput = null;
+ serverOutput = null;
+ }
+
+ /** Return server connection status */
+ public boolean serverIsOpen() {
+ return serverSocket != null;
+ }
+
+ /** Create connection with host <i>host</i> on port <i>port</i> */
+ public NetworkClient(String host, int port) throws IOException {
+ openServer(host, port);
+ }
+
+ public NetworkClient() {
+ }
+}
diff --git a/base/util/src/netscape/net/TransferProtocolClient.java b/base/util/src/netscape/net/TransferProtocolClient.java
new file mode 100644
index 000000000..76e3a9c21
--- /dev/null
+++ b/base/util/src/netscape/net/TransferProtocolClient.java
@@ -0,0 +1,127 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.net;
+
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * This class implements that basic intefaces of transfer protocols.
+ * It is used by subclasses implementing specific protocols.
+ *
+ * @version 1.25, 08/07/97
+ * @author Jonathan Payne
+ */
+
+public class TransferProtocolClient extends NetworkClient {
+ static final boolean debug = false;
+
+ /**
+ * Array of strings (usually 1 entry) for the last reply
+ * from the server.
+ */
+ protected Vector<String> serverResponse = new Vector<String>(1);
+
+ /** code for last reply */
+ protected int lastReplyCode;
+
+ /**
+ * Pulls the response from the server and returns the code as a
+ * number. Returns -1 on failure.
+ */
+ public int readServerResponse() throws IOException {
+ StringBuffer replyBuf = new StringBuffer(32);
+ int c;
+ int continuingCode = -1;
+ int code;
+ String response;
+
+ serverResponse.setSize(0);
+ while (true) {
+ while ((c = serverInput.read()) != -1) {
+ if (c == '\r') {
+ if ((c = serverInput.read()) != '\n')
+ replyBuf.append('\r');
+ }
+ replyBuf.append((char) c);
+ if (c == '\n')
+ break;
+ }
+ response = replyBuf.toString();
+ replyBuf.setLength(0);
+ if (debug) {
+ System.out.print(response);
+ }
+ try {
+ code = Integer.parseInt(response.substring(0, 3));
+ } catch (NumberFormatException e) {
+ code = -1;
+ } catch (StringIndexOutOfBoundsException e) {
+ /* this line doesn't contain a response code, so
+ we just completely ignore it */
+ continue;
+ }
+ serverResponse.addElement(response);
+ if (continuingCode != -1) {
+ /* we've seen a XXX- sequence */
+ if (code != continuingCode ||
+ (response.length() >= 4 && response.charAt(3) == '-')) {
+ continue;
+ } else {
+ /* seen the end of code sequence */
+ continuingCode = -1;
+ break;
+ }
+ } else if (response.length() >= 4 && response.charAt(3) == '-') {
+ continuingCode = code;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ return lastReplyCode = code;
+ }
+
+ /** Sends command <i>cmd</i> to the server. */
+ public void sendServer(String cmd) {
+ serverOutput.print(cmd);
+ if (debug) {
+ System.out.print("Sending: " + cmd);
+ }
+ }
+
+ /** converts the server response into a string. */
+ public String getResponseString() {
+ return (String) serverResponse.elementAt(0);
+ }
+
+ /** Returns all server response strings. */
+ public Vector<String> getResponseStrings() {
+ return serverResponse;
+ }
+
+ /** standard constructor to host <i>host</i>, port <i>port</i>. */
+ public TransferProtocolClient(String host, int port) throws IOException {
+ super(host, port);
+ }
+
+ /** creates an uninitialized instance of this class. */
+ public TransferProtocolClient() {
+ }
+}
diff --git a/base/util/src/netscape/net/smtp/SmtpClient.java b/base/util/src/netscape/net/smtp/SmtpClient.java
new file mode 100644
index 000000000..40b927b8f
--- /dev/null
+++ b/base/util/src/netscape/net/smtp/SmtpClient.java
@@ -0,0 +1,235 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.net.smtp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
+
+import netscape.net.TransferProtocolClient;
+
+/**
+ * This class implements the SMTP client.
+ * You can send a piece of mail by creating a new SmtpClient, calling
+ * the "to" method to add destinations, calling "from" to name the
+ * sender, calling startMessage to return a stream to which you write
+ * the message (with RFC733 headers) and then you finally close the Smtp
+ * Client.
+ *
+ * @version 1.17, 12 Dec 1994
+ * @author James Gosling
+ */
+
+public class SmtpClient extends TransferProtocolClient {
+ SmtpPrintStream message;
+
+ /**
+ * issue the QUIT command to the SMTP server and close the connection.
+ */
+ public void closeServer() throws IOException {
+ if (serverIsOpen()) {
+ closeMessage();
+ issueCommand("QUIT\r\n", 221);
+ super.closeServer();
+ }
+ }
+
+ void issueCommand(String cmd, int expect) throws IOException {
+ sendServer(cmd);
+ int reply;
+ while ((reply = readServerResponse()) != expect)
+ if (reply != 220) {
+ throw new SmtpProtocolException(getResponseString());
+ }
+ }
+
+ private void toCanonical(String s) throws IOException {
+ issueCommand("rcpt to: " + s + "\r\n", 250);
+ }
+
+ public void to(String s) throws IOException {
+ int st = 0;
+ int limit = s.length();
+ int pos = 0;
+ int lastnonsp = 0;
+ int parendepth = 0;
+ boolean ignore = false;
+ while (pos < limit) {
+ int c = s.charAt(pos);
+ if (parendepth > 0) {
+ if (c == '(')
+ parendepth++;
+ else if (c == ')')
+ parendepth--;
+ if (parendepth == 0)
+ if (lastnonsp > st)
+ ignore = true;
+ else
+ st = pos + 1;
+ } else if (c == '(')
+ parendepth++;
+ else if (c == '<')
+ st = lastnonsp = pos + 1;
+ else if (c == '>')
+ ignore = true;
+ else if (c == ',') {
+ if (lastnonsp > st)
+ toCanonical(s.substring(st, lastnonsp));
+ st = pos + 1;
+ ignore = false;
+ } else {
+ if (c > ' ' && !ignore)
+ lastnonsp = pos + 1;
+ else if (st == pos)
+ st++;
+ }
+ pos++;
+ }
+ if (lastnonsp > st)
+ toCanonical(s.substring(st, lastnonsp));
+ }
+
+ public void from(String s) throws IOException {
+ issueCommand("mail from: " + s + "\r\n", 250);
+ }
+
+ /** open a SMTP connection to host <i>host</i>. */
+ private void openServer(String host) throws IOException {
+ openServer(host, 25);
+ issueCommand("helo " + InetAddress.getLocalHost().getHostName() + "\r\n", 250);
+ }
+
+ public PrintStream startMessage() throws IOException {
+ issueCommand("data\r\n", 354);
+ return message = new SmtpPrintStream(serverOutput, this);
+ }
+
+ void closeMessage() throws IOException {
+ if (message != null)
+ message.close();
+ }
+
+ /** New SMTP client connected to host <i>host</i>. */
+ public SmtpClient(String host) throws IOException {
+ super();
+ if (host != null) {
+ try {
+ openServer(host);
+ return;
+ } catch (Exception e) {
+ }
+ }
+ try {
+ String s;
+ try {
+ // java.security.AccessController.beginPrivileged();
+ s = System.getProperty("mail.host");
+ } finally {
+ // java.security.AccessController.endPrivileged();
+ }
+ if (s != null) {
+ openServer(s);
+ return;
+ }
+ } catch (Exception e) {
+ }
+ try {
+ openServer("localhost");
+ } catch (Exception e) {
+ openServer("mailhost");
+ }
+ }
+
+ /** Create an uninitialized SMTP client. */
+ public SmtpClient() throws IOException {
+ this(null);
+ }
+}
+
+class SmtpPrintStream extends java.io.PrintStream {
+ private SmtpClient target;
+ private int lastc = '\n';
+
+ SmtpPrintStream(OutputStream fos, SmtpClient cl) {
+ super(fos);
+ target = cl;
+ }
+
+ public void close() {
+ if (target == null)
+ return;
+ if (lastc != '\n') {
+ write('\r');
+ write('\n');
+ }
+ try {
+ target.issueCommand(".\r\n", 250);
+ target.message = null;
+ out = null;
+ target = null;
+ } catch (IOException e) {
+ }
+ }
+
+ public void write(int b) {
+ try {
+ // quote a dot at the beginning of a line
+ if (lastc == '\n' && b == '.') {
+ out.write('.');
+ }
+
+ // translate NL to CRLF
+ if (b == '\n') {
+ out.write('\r');
+ }
+ out.write(b);
+ lastc = b;
+ } catch (IOException e) {
+ }
+ }
+
+ public void write(byte b[], int off, int len) {
+ try {
+ int lc = lastc;
+ while (--len >= 0) {
+ int c = b[off++];
+
+ // quote a dot at the beginning of a line
+ if (lc == '\n' && c == '.')
+ out.write('.');
+
+ // translate NL to CRLF
+ if (c == '\n') {
+ out.write('\r');
+ }
+ out.write(c);
+ lc = c;
+ }
+ lastc = lc;
+ } catch (IOException e) {
+ }
+ }
+
+ public void print(String s) {
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
+ write(s.charAt(i));
+ }
+ }
+}
diff --git a/base/util/src/netscape/net/smtp/SmtpProtocolException.java b/base/util/src/netscape/net/smtp/SmtpProtocolException.java
new file mode 100644
index 000000000..9ffe5d95b
--- /dev/null
+++ b/base/util/src/netscape/net/smtp/SmtpProtocolException.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.net.smtp;
+
+import java.io.IOException;
+
+/**
+ * This exeception is thrown when unexpected results are returned during
+ * an SMTP session.
+ */
+public class SmtpProtocolException extends IOException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5586603317525864401L;
+
+ SmtpProtocolException(String s) {
+ super(s);
+ }
+}
diff --git a/base/util/src/netscape/security/acl/AclEntryImpl.java b/base/util/src/netscape/security/acl/AclEntryImpl.java
new file mode 100644
index 000000000..46365f5d8
--- /dev/null
+++ b/base/util/src/netscape/security/acl/AclEntryImpl.java
@@ -0,0 +1,182 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+import java.security.acl.AclEntry;
+import java.security.acl.Group;
+import java.security.acl.Permission;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * This is a class that describes one entry that associates users
+ * or groups with permissions in the ACL.
+ * The entry may be used as a way of granting or denying permissions.
+ *
+ * @author Satish Dharmaraj
+ */
+public class AclEntryImpl implements AclEntry {
+ private Principal user = null;
+ private Vector<Permission> permissionSet = new Vector<Permission>(10, 10);
+ private boolean negative = false;
+
+ /**
+ * Construct an ACL entry that associates a user with permissions
+ * in the ACL.
+ *
+ * @param user The user that is associated with this entry.
+ */
+ public AclEntryImpl(Principal user) {
+ this.user = user;
+ }
+
+ /**
+ * Construct a null ACL entry
+ */
+ public AclEntryImpl() {
+ }
+
+ /**
+ * Sets the principal in the entity. If a group or a
+ * principal had already been set, a false value is
+ * returned, otherwise a true value is returned.
+ *
+ * @param user The user that is associated with this entry.
+ * @return true if the principal is set, false if there is
+ * one already.
+ */
+ public boolean setPrincipal(Principal user) {
+ if (this.user != null)
+ return false;
+ this.user = user;
+ return true;
+ }
+
+ /**
+ * This method sets the ACL to have negative permissions.
+ * That is the user or group is denied the permission set
+ * specified in the entry.
+ */
+ public void setNegativePermissions() {
+ negative = true;
+ }
+
+ /**
+ * Returns true if this is a negative ACL.
+ */
+ public boolean isNegative() {
+ return negative;
+ }
+
+ /**
+ * A principal or a group can be associated with multiple
+ * permissions. This method adds a permission to the ACL entry.
+ *
+ * @param permission The permission to be associated with
+ * the principal or the group in the entry.
+ * @return true if the permission was added, false if the
+ * permission was already part of the permission set.
+ */
+ public boolean addPermission(Permission permission) {
+
+ if (permissionSet.contains(permission))
+ return false;
+
+ permissionSet.addElement(permission);
+
+ return true;
+ }
+
+ /**
+ * The method disassociates the permission from the Principal
+ * or the Group in this ACL entry.
+ *
+ * @param permission The permission to be disassociated with
+ * the principal or the group in the entry.
+ * @return true if the permission is removed, false if the
+ * permission is not part of the permission set.
+ */
+ public boolean removePermission(Permission permission) {
+ return permissionSet.removeElement(permission);
+ }
+
+ /**
+ * Checks if the passed permission is part of the allowed
+ * permission set in this entry.
+ *
+ * @param permission The permission that has to be part of
+ * the permission set in the entry.
+ * @return true if the permission passed is part of the
+ * permission set in the entry, false otherwise.
+ */
+ public boolean checkPermission(Permission permission) {
+ return permissionSet.contains(permission);
+ }
+
+ /**
+ * return an enumeration of the permissions in this ACL entry.
+ */
+ public Enumeration<Permission> permissions() {
+ return permissionSet.elements();
+ }
+
+ /**
+ * Return a string representation of the contents of the ACL entry.
+ */
+ public String toString() {
+ StringBuffer s = new StringBuffer();
+ if (negative)
+ s.append("-");
+ else
+ s.append("+");
+ if (user instanceof Group)
+ s.append("Group.");
+ else
+ s.append("User.");
+ s.append(user + "=");
+ Enumeration<Permission> e = permissions();
+ while (e.hasMoreElements()) {
+ Permission p = (Permission) e.nextElement();
+ s.append(p);
+ if (e.hasMoreElements())
+ s.append(",");
+ }
+ return new String(s);
+ }
+
+ /**
+ * Clones an AclEntry.
+ */
+ public synchronized Object clone() {
+ AclEntryImpl cloned;
+ cloned = new AclEntryImpl(user);
+ cloned.permissionSet = new Vector<Permission>(permissionSet);
+ cloned.negative = negative;
+ return cloned;
+ }
+
+ /**
+ * Return the Principal associated in this ACL entry.
+ * The method returns null if the entry uses a group
+ * instead of a principal.
+ */
+ public Principal getPrincipal() {
+ return user;
+ }
+}
diff --git a/base/util/src/netscape/security/acl/AclImpl.java b/base/util/src/netscape/security/acl/AclImpl.java
new file mode 100644
index 000000000..76750b7b9
--- /dev/null
+++ b/base/util/src/netscape/security/acl/AclImpl.java
@@ -0,0 +1,391 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+import java.security.acl.Acl;
+import java.security.acl.AclEntry;
+import java.security.acl.Group;
+import java.security.acl.NotOwnerException;
+import java.security.acl.Permission;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+
+/**
+ * An Access Control List (ACL) is encapsulated by this class.
+ *
+ * @author Satish Dharmaraj
+ */
+public class AclImpl extends OwnerImpl implements Acl {
+ //
+ // Maintain four tables. one each for positive and negative
+ // ACLs. One each depending on whether the entity is a group
+ // or principal.
+ //
+ private Hashtable<Principal, AclEntry> allowedUsersTable = new Hashtable<Principal, AclEntry>(23);
+ private Hashtable<Principal, AclEntry> allowedGroupsTable = new Hashtable<Principal, AclEntry>(23);
+ private Hashtable<Principal, AclEntry> deniedUsersTable = new Hashtable<Principal, AclEntry>(23);
+ private Hashtable<Principal, AclEntry> deniedGroupsTable = new Hashtable<Principal, AclEntry>(23);
+ private String aclName = null;
+ private Vector<Permission> zeroSet = new Vector<Permission>(1, 1);
+
+ /**
+ * Constructor for creating an empty ACL.
+ */
+ public AclImpl(Principal owner, String name) {
+ super(owner);
+ try {
+ setName(owner, name);
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Sets the name of the ACL.
+ *
+ * @param caller the principal who is invoking this method.
+ * @param name the name of the ACL.
+ * @exception NotOwnerException if the caller principal is
+ * not on the owners list of the Acl.
+ */
+ public void setName(Principal caller, String name)
+ throws NotOwnerException {
+ if (!isOwner(caller))
+ throw new NotOwnerException();
+
+ aclName = name;
+ }
+
+ /**
+ * Returns the name of the ACL.
+ *
+ * @return the name of the ACL.
+ */
+ public String getName() {
+ return aclName;
+ }
+
+ /**
+ * Adds an ACL entry to this ACL. An entry associates a
+ * group or a principal with a set of permissions. Each
+ * user or group can have one positive ACL entry and one
+ * negative ACL entry. If there is one of the type (negative
+ * or positive) already in the table, a false value is returned.
+ * The caller principal must be a part of the owners list of
+ * the ACL in order to invoke this method.
+ *
+ * @param caller the principal who is invoking this method.
+ * @param entry the ACL entry that must be added to the ACL.
+ * @return true on success, false if the entry is already present.
+ * @exception NotOwnerException if the caller principal
+ * is not on the owners list of the Acl.
+ */
+ public synchronized boolean addEntry(Principal caller, AclEntry entry)
+ throws NotOwnerException {
+ if (!isOwner(caller))
+ throw new NotOwnerException();
+
+ Hashtable<Principal, AclEntry> aclTable = findTable(entry);
+ Principal key = entry.getPrincipal();
+
+ if (aclTable.get(key) != null)
+ return false;
+
+ aclTable.put(key, entry);
+ return true;
+ }
+
+ /**
+ * Removes an ACL entry from this ACL.
+ * The caller principal must be a part of the owners list of the ACL
+ * in order to invoke this method.
+ *
+ * @param caller the principal who is invoking this method.
+ * @param entry the ACL entry that must be removed from the ACL.
+ * @return true on success, false if the entry is not part of the ACL.
+ * @exception NotOwnerException if the caller principal is not
+ * the owners list of the Acl.
+ */
+ public synchronized boolean removeEntry(Principal caller, AclEntry entry)
+ throws NotOwnerException {
+ if (!isOwner(caller))
+ throw new NotOwnerException();
+
+ Hashtable<Principal, AclEntry> aclTable = findTable(entry);
+ Object key = entry.getPrincipal();
+
+ Object o = aclTable.remove(key);
+ return (o != null);
+ }
+
+ /**
+ * This method returns the set of allowed permissions for the
+ * specified principal. This set of allowed permissions is calculated
+ * as follows:
+ *
+ * If there is no entry for a group or a principal an empty permission
+ * set is assumed.
+ *
+ * The group positive permission set is the union of all
+ * the positive permissions of each group that the individual belongs to.
+ * The group negative permission set is the union of all
+ * the negative permissions of each group that the individual belongs to.
+ * If there is a specific permission that occurs in both
+ * the postive permission set and the negative permission set,
+ * it is removed from both. The group positive and negatoive permission
+ * sets are calculated.
+ *
+ * The individial positive permission set and the individual negative
+ * permission set is then calculated. Again abscence of an entry means
+ * the empty set.
+ *
+ * The set of permissions granted to the principal is then calculated using
+ * the simple rule: Individual permissions always override the Group permissions.
+ * Specifically, individual negative permission set (specific
+ * denial of permissions) overrides the group positive permission set.
+ * And the individual positive permission set override the group negative
+ * permission set.
+ *
+ * @param user the principal for which the ACL entry is returned.
+ * @return The resulting permission set that the principal is allowed.
+ */
+ public synchronized Enumeration<Permission> getPermissions(Principal user) {
+
+ Enumeration<Permission> individualPositive;
+ Enumeration<Permission> individualNegative;
+ Enumeration<Permission> groupPositive;
+ Enumeration<Permission> groupNegative;
+
+ //
+ // canonicalize the sets. That is remove common permissions from
+ // positive and negative sets.
+ //
+ groupPositive = subtract(getGroupPositive(user), getGroupNegative(user));
+ groupNegative = subtract(getGroupNegative(user), getGroupPositive(user));
+ individualPositive = subtract(getIndividualPositive(user), getIndividualNegative(user));
+ individualNegative = subtract(getIndividualNegative(user), getIndividualPositive(user));
+
+ //
+ // net positive permissions is individual positive permissions
+ // plus (group positive - individual negative).
+ //
+ Enumeration<Permission> temp1 = subtract(groupPositive, individualNegative);
+ Enumeration<Permission> netPositive = union(individualPositive, temp1);
+
+ // recalculate the enumeration since we lost it in performing the
+ // subtraction
+ //
+ individualPositive = subtract(getIndividualPositive(user), getIndividualNegative(user));
+ individualNegative = subtract(getIndividualNegative(user), getIndividualPositive(user));
+
+ //
+ // net negative permissions is individual negative permissions
+ // plus (group negative - individual positive).
+ //
+ temp1 = subtract(groupNegative, individualPositive);
+ Enumeration<Permission> netNegative = union(individualNegative, temp1);
+
+ return subtract(netPositive, netNegative);
+ }
+
+ /**
+ * This method checks whether or not the specified principal
+ * has the required permission. If permission is denied
+ * permission false is returned, a true value is returned otherwise.
+ * This method does not authenticate the principal. It presumes that
+ * the principal is a valid authenticated principal.
+ *
+ * @param principal the name of the authenticated principal
+ * @param permission the permission that the principal must have.
+ * @return true of the principal has the permission desired, false
+ * otherwise.
+ */
+ public boolean checkPermission(Principal principal, Permission permission) {
+ Enumeration<Permission> permSet = getPermissions(principal);
+ while (permSet.hasMoreElements()) {
+ Permission p = (Permission) permSet.nextElement();
+ if (p.equals(permission))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * returns an enumeration of the entries in this ACL.
+ */
+ public synchronized Enumeration<AclEntry> entries() {
+ return new AclEnumerator(this,
+ allowedUsersTable, allowedGroupsTable,
+ deniedUsersTable, deniedGroupsTable);
+ }
+
+ /**
+ * return a stringified version of the
+ * ACL.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ Enumeration<AclEntry> entries = entries();
+ while (entries.hasMoreElements()) {
+ AclEntry entry = (AclEntry) entries.nextElement();
+ sb.append(entry.toString().trim());
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ //
+ // Find the table that this entry belongs to. There are 4
+ // tables that are maintained. One each for postive and
+ // negative ACLs and one each for groups and users.
+ // This method figures out which
+ // table is the one that this AclEntry belongs to.
+ //
+ private Hashtable<Principal, AclEntry> findTable(AclEntry entry) {
+ Hashtable<Principal, AclEntry> aclTable = null;
+
+ Principal p = entry.getPrincipal();
+ if (p instanceof Group) {
+ if (entry.isNegative())
+ aclTable = deniedGroupsTable;
+ else
+ aclTable = allowedGroupsTable;
+ } else {
+ if (entry.isNegative())
+ aclTable = deniedUsersTable;
+ else
+ aclTable = allowedUsersTable;
+ }
+ return aclTable;
+ }
+
+ //
+ // returns the set e1 U e2.
+ //
+ private <T> Enumeration<T> union(Enumeration<T> e1, Enumeration<T> e2) {
+ Vector<T> v = new Vector<T>(20, 20);
+
+ while (e1.hasMoreElements())
+ v.addElement(e1.nextElement());
+
+ while (e2.hasMoreElements()) {
+ T o = e2.nextElement();
+ if (!v.contains(o))
+ v.addElement(o);
+ }
+
+ return v.elements();
+ }
+
+ //
+ // returns the set e1 - e2.
+ //
+ private <T> Enumeration<T> subtract(Enumeration<T> e1, Enumeration<T> e2) {
+ Vector<T> v = new Vector<T>(20, 20);
+
+ while (e1.hasMoreElements())
+ v.addElement(e1.nextElement());
+
+ while (e2.hasMoreElements()) {
+ T o = e2.nextElement();
+ if (v.contains(o))
+ v.removeElement(o);
+ }
+
+ return v.elements();
+ }
+
+ private Enumeration<Permission> getGroupPositive(Principal user) {
+ Enumeration<Permission> groupPositive = zeroSet.elements();
+ Enumeration<Principal> e = allowedGroupsTable.keys();
+ while (e.hasMoreElements()) {
+ Group g = (Group) e.nextElement();
+ if (g.isMember(user)) {
+ AclEntry ae = (AclEntry) allowedGroupsTable.get(g);
+ groupPositive = union(ae.permissions(), groupPositive);
+ }
+ }
+ return groupPositive;
+ }
+
+ private Enumeration<Permission> getGroupNegative(Principal user) {
+ Enumeration<Permission> groupNegative = zeroSet.elements();
+ Enumeration<Principal> e = deniedGroupsTable.keys();
+ while (e.hasMoreElements()) {
+ Group g = (Group) e.nextElement();
+ if (g.isMember(user)) {
+ AclEntry ae = (AclEntry) deniedGroupsTable.get(g);
+ groupNegative = union(ae.permissions(), groupNegative);
+ }
+ }
+ return groupNegative;
+ }
+
+ private Enumeration<Permission> getIndividualPositive(Principal user) {
+ Enumeration<Permission> individualPositive = zeroSet.elements();
+ AclEntry ae = (AclEntry) allowedUsersTable.get(user);
+ if (ae != null)
+ individualPositive = ae.permissions();
+ return individualPositive;
+ }
+
+ private Enumeration<Permission> getIndividualNegative(Principal user) {
+ Enumeration<Permission> individualNegative = zeroSet.elements();
+ AclEntry ae = (AclEntry) deniedUsersTable.get(user);
+ if (ae != null)
+ individualNegative = ae.permissions();
+ return individualNegative;
+ }
+}
+
+final class AclEnumerator implements Enumeration<AclEntry> {
+ Acl acl;
+ Enumeration<AclEntry> u1, u2, g1, g2;
+
+ AclEnumerator(Acl acl, Hashtable<Principal, AclEntry> u1, Hashtable<Principal, AclEntry> g1,
+ Hashtable<Principal, AclEntry> u2, Hashtable<Principal, AclEntry> g2) {
+ this.acl = acl;
+ this.u1 = u1.elements();
+ this.u2 = u2.elements();
+ this.g1 = g1.elements();
+ this.g2 = g2.elements();
+ }
+
+ public boolean hasMoreElements() {
+ return (u1.hasMoreElements() ||
+ u2.hasMoreElements() ||
+ g1.hasMoreElements() || g2.hasMoreElements());
+ }
+
+ public AclEntry nextElement() {
+ synchronized (acl) {
+ if (u1.hasMoreElements())
+ return u1.nextElement();
+ if (u2.hasMoreElements())
+ return u2.nextElement();
+ if (g1.hasMoreElements())
+ return g1.nextElement();
+ if (g2.hasMoreElements())
+ return g2.nextElement();
+ }
+ throw new NoSuchElementException("Acl Enumerator");
+ }
+}
diff --git a/base/util/src/netscape/security/acl/AllPermissionsImpl.java b/base/util/src/netscape/security/acl/AllPermissionsImpl.java
new file mode 100644
index 000000000..f2b57742f
--- /dev/null
+++ b/base/util/src/netscape/security/acl/AllPermissionsImpl.java
@@ -0,0 +1,43 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.acl.Permission;
+
+/**
+ * This class implements the principal interface for the set of all permissions.
+ *
+ * @author Satish Dharmaraj
+ */
+public class AllPermissionsImpl extends PermissionImpl {
+
+ public AllPermissionsImpl(String s) {
+ super(s);
+ }
+
+ /**
+ * This function returns true if the permission passed matches the permission represented in
+ * this interface.
+ *
+ * @param another The Permission object to compare with.
+ * @return true always
+ */
+ public boolean equals(Permission another) {
+ return true;
+ }
+}
diff --git a/base/util/src/netscape/security/acl/GroupImpl.java b/base/util/src/netscape/security/acl/GroupImpl.java
new file mode 100644
index 000000000..ed087a544
--- /dev/null
+++ b/base/util/src/netscape/security/acl/GroupImpl.java
@@ -0,0 +1,173 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * This class implements a group of principals.
+ *
+ * @author Satish Dharmaraj
+ */
+public class GroupImpl implements Group {
+ private Vector<Principal> groupMembers = new Vector<Principal>(50, 100);
+ private String group;
+
+ /**
+ * Constructs a Group object with no members.
+ *
+ * @param groupName the name of the group
+ */
+ public GroupImpl(String groupName) {
+ this.group = groupName;
+ }
+
+ /**
+ * adds the specified member to the group.
+ *
+ * @param user The principal to add to the group.
+ * @return true if the member was added - false if the
+ * member could not be added.
+ */
+ public boolean addMember(Principal user) {
+ if (groupMembers.contains(user))
+ return false;
+
+ // do not allow groups to be added to itself.
+ if (group.equals(user.toString()))
+ throw new IllegalArgumentException();
+
+ groupMembers.addElement(user);
+ return true;
+ }
+
+ /**
+ * removes the specified member from the group.
+ *
+ * @param user The principal to remove from the group.
+ * @param true if the principal was removed false if
+ * the principal was not a member
+ */
+ public boolean removeMember(Principal user) {
+ return groupMembers.removeElement(user);
+ }
+
+ /**
+ * returns the enumeration of the members in the group.
+ */
+ public Enumeration<Principal> members() {
+ return groupMembers.elements();
+ }
+
+ /**
+ * This function returns true if the group passed matches
+ * the group represented in this interface.
+ *
+ * @param another The group to compare this group to.
+ */
+ public boolean equals(Group another) {
+ return group.equals(another.toString());
+ }
+
+ /**
+ * Prints a stringified version of the group.
+ */
+ public String toString() {
+ return group;
+ }
+
+ /**
+ * return a hashcode for the principal.
+ */
+ public int hashCode() {
+ return group.hashCode();
+ }
+
+ /**
+ * returns true if the passed principal is a member of the group.
+ *
+ * @param member The principal whose membership must be checked for.
+ * @return true if the principal is a member of this group,
+ * false otherwise
+ */
+ public boolean isMember(Principal member) {
+
+ //
+ // if the member is part of the group (common case), return true.
+ // if not, recursively search depth first in the group looking for the
+ // principal.
+ //
+ if (groupMembers.contains(member)) {
+ return true;
+ } else {
+ Vector<Group> alreadySeen = new Vector<Group>(10);
+ return isMemberRecurse(member, alreadySeen);
+ }
+ }
+
+ /**
+ * return the name of the principal.
+ */
+ public String getName() {
+ return group;
+ }
+
+ //
+ // This function is the recursive search of groups for this
+ // implementation of the Group. The search proceeds building up
+ // a vector of already seen groups. Only new groups are considered,
+ // thereby avoiding loops.
+ //
+ boolean isMemberRecurse(Principal member, Vector<Group> alreadySeen) {
+ Enumeration<Principal> e = members();
+ while (e.hasMoreElements()) {
+ boolean mem = false;
+ Principal p = e.nextElement();
+
+ // if the member is in this collection, return true
+ if (p.equals(member)) {
+ return true;
+ } else if (p instanceof GroupImpl) {
+ //
+ // if not recurse if the group has not been checked already.
+ // Can call method in this package only if the object is an
+ // instance of this class. Otherwise call the method defined
+ // in the interface. (This can lead to a loop if a mixture of
+ // implementations form a loop, but we live with this improbable
+ // case rather than clutter the interface by forcing the
+ // implementation of this method.)
+ //
+ GroupImpl g = (GroupImpl) p;
+ alreadySeen.addElement(this);
+ if (!alreadySeen.contains(g))
+ mem = g.isMemberRecurse(member, alreadySeen);
+ } else if (p instanceof Group) {
+ Group g = (Group) p;
+ if (!alreadySeen.contains(g))
+ mem = g.isMember(member);
+ }
+
+ if (mem)
+ return mem;
+ }
+ return false;
+ }
+}
diff --git a/base/util/src/netscape/security/acl/OwnerImpl.java b/base/util/src/netscape/security/acl/OwnerImpl.java
new file mode 100644
index 000000000..3f47a1dd8
--- /dev/null
+++ b/base/util/src/netscape/security/acl/OwnerImpl.java
@@ -0,0 +1,105 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.security.acl.LastOwnerException;
+import java.security.acl.NotOwnerException;
+import java.security.acl.Owner;
+import java.util.Enumeration;
+
+/**
+ * Class implementing the Owner interface. The
+ * initial owner principal is configured as
+ * part of the constructor.
+ *
+ * @author Satish Dharmaraj
+ */
+public class OwnerImpl implements Owner {
+ private Group ownerGroup;
+
+ public OwnerImpl(Principal owner) {
+ ownerGroup = new GroupImpl("AclOwners");
+ ownerGroup.addMember(owner);
+ }
+
+ /**
+ * Adds an owner. Owners can modify ACL contents and can disassociate
+ * ACLs from the objects they protect in the AclConfig interface.
+ * The caller principal must be a part of the owners list of the ACL in
+ * order to invoke this method. The initial owner is configured
+ * at ACL construction time.
+ *
+ * @param caller the principal who is invoking this method.
+ * @param owner The owner that should be added to the owners list.
+ * @return true if success, false if already an owner.
+ * @exception NotOwnerException if the caller principal is not on
+ * the owners list of the Acl.
+ */
+ public synchronized boolean addOwner(Principal caller, Principal owner)
+ throws NotOwnerException {
+ if (!isOwner(caller))
+ throw new NotOwnerException();
+
+ ownerGroup.addMember(owner);
+ return false;
+ }
+
+ /**
+ * Delete owner. If this is the last owner in the ACL, an exception is
+ * raised.
+ * The caller principal must be a part of the owners list of the ACL in
+ * order to invoke this method.
+ *
+ * @param caller the principal who is invoking this method.
+ * @param owner The owner to be removed from the owners list.
+ * @return true if the owner is removed, false if the owner is not part
+ * of the owners list.
+ * @exception NotOwnerException if the caller principal is not on
+ * the owners list of the Acl.
+ * @exception LastOwnerException if there is only one owner left in the group, then
+ * deleteOwner would leave the ACL owner-less. This exception is raised in such a case.
+ */
+ public synchronized boolean deleteOwner(Principal caller, Principal owner)
+ throws NotOwnerException, LastOwnerException {
+ if (!isOwner(caller))
+ throw new NotOwnerException();
+
+ Enumeration<? extends Principal> e = ownerGroup.members();
+ //
+ // check if there is atleast 2 members left.
+ //
+ e.nextElement(); // consume next element
+ if (e.hasMoreElements())
+ return ownerGroup.removeMember(owner);
+ else
+ throw new LastOwnerException();
+
+ }
+
+ /**
+ * returns if the given principal belongs to the owner list.
+ *
+ * @param owner The owner to check if part of the owners list
+ * @return true if the passed principal is in the owner list, false if not.
+ */
+ public synchronized boolean isOwner(Principal owner) {
+ return ownerGroup.isMember(owner);
+ }
+}
diff --git a/base/util/src/netscape/security/acl/PermissionImpl.java b/base/util/src/netscape/security/acl/PermissionImpl.java
new file mode 100644
index 000000000..2e73d3c7e
--- /dev/null
+++ b/base/util/src/netscape/security/acl/PermissionImpl.java
@@ -0,0 +1,65 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.acl.Permission;
+
+/**
+ * The PermissionImpl class implements the permission
+ * interface for permissions that are strings.
+ *
+ * @author Satish Dharmaraj
+ */
+public class PermissionImpl implements Permission {
+
+ private String permission;
+
+ /**
+ * Construct a permission object using a string.
+ *
+ * @param permission the stringified version of the permission.
+ */
+ public PermissionImpl(String permission) {
+ this.permission = permission;
+ }
+
+ /**
+ * This function returns true if the object passed matches the permission
+ * represented in this interface.
+ *
+ * @param another The Permission object to compare with.
+ * @return true if the Permission objects are equal, false otherwise
+ */
+ public boolean equals(Object another) {
+ if (another instanceof Permission) {
+ Permission p = (Permission) another;
+ return permission.equals(p.toString());
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Prints a stringified version of the permission.
+ *
+ * @return the string representation of the Permission.
+ */
+ public String toString() {
+ return permission;
+ }
+}
diff --git a/base/util/src/netscape/security/acl/PrincipalImpl.java b/base/util/src/netscape/security/acl/PrincipalImpl.java
new file mode 100644
index 000000000..25fa11095
--- /dev/null
+++ b/base/util/src/netscape/security/acl/PrincipalImpl.java
@@ -0,0 +1,77 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+
+/**
+ * This class implements the principal interface.
+ *
+ * @author Satish Dharmaraj
+ */
+public class PrincipalImpl implements Principal {
+
+ private String user;
+
+ /**
+ * Construct a principal from a string user name.
+ *
+ * @param user The string form of the principal name.
+ */
+ public PrincipalImpl(String user) {
+ this.user = user;
+ }
+
+ /**
+ * This function returns true if the object passed matches
+ * the principal represented in this implementation
+ *
+ * @param another the Principal to compare with.
+ * @return true if the Principal passed is the same as that
+ * encapsulated in this object, false otherwise
+ */
+ public boolean equals(Object another) {
+ if (another instanceof PrincipalImpl) {
+ PrincipalImpl p = (PrincipalImpl) another;
+ return user.equals(p.toString());
+ } else
+ return false;
+ }
+
+ /**
+ * Prints a stringified version of the principal.
+ */
+ public String toString() {
+ return user;
+ }
+
+ /**
+ * return a hashcode for the principal.
+ */
+ public int hashCode() {
+ return user.hashCode();
+ }
+
+ /**
+ * return the name of the principal.
+ */
+ public String getName() {
+ return user;
+ }
+
+}
diff --git a/base/util/src/netscape/security/acl/WorldGroupImpl.java b/base/util/src/netscape/security/acl/WorldGroupImpl.java
new file mode 100644
index 000000000..2f885cbec
--- /dev/null
+++ b/base/util/src/netscape/security/acl/WorldGroupImpl.java
@@ -0,0 +1,42 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.acl;
+
+import java.security.Principal;
+
+/**
+ * This class implements a group of principals.
+ *
+ * @author Satish Dharmaraj
+ */
+public class WorldGroupImpl extends GroupImpl {
+
+ public WorldGroupImpl(String s) {
+ super(s);
+ }
+
+ /**
+ * returns true for all passed principals
+ *
+ * @param member The principal whose membership must be checked in this Group.
+ * @return true always since this is the "world" group.
+ */
+ public boolean isMember(Principal member) {
+ return true;
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/AccessDescription.java b/base/util/src/netscape/security/extensions/AccessDescription.java
new file mode 100644
index 000000000..f13c937e7
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/AccessDescription.java
@@ -0,0 +1,76 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.GeneralName;
+
+public class AccessDescription implements Serializable {
+ ObjectIdentifier mOID = null;
+ GeneralName mLocation = null;
+
+ AccessDescription(ObjectIdentifier oid, GeneralName location) {
+ mOID = oid;
+ mLocation = location;
+ }
+
+ public ObjectIdentifier getMethod() {
+ return mOID;
+ }
+
+ public GeneralName getLocation() {
+ return mLocation;
+ }
+
+ /**
+ * For serialization:
+ * Note that GeneralName is not serializable. That is
+ * why we need to define our own serialization method.
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ tmp.putOID(mOID);
+ mLocation.encode(tmp);
+ seq.write(DerValue.tag_Sequence, tmp);
+ out.write(seq.toByteArray());
+ }
+
+ /**
+ * For serialization
+ * Note that GeneralName is not serializable. That is
+ * why we need to define our own serialization method.
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException {
+ DerValue val = new DerValue(in);
+ DerValue seq = val.data.getDerValue();
+
+ mOID = seq.getOID();
+ DerValue derLoc = val.data.getDerValue();
+
+ mLocation = new GeneralName(derLoc);
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/AuthInfoAccessExtension.java b/base/util/src/netscape/security/extensions/AuthInfoAccessExtension.java
new file mode 100644
index 000000000..b8e2933dd
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/AuthInfoAccessExtension.java
@@ -0,0 +1,272 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.GeneralName;
+import netscape.security.x509.URIName;
+
+/**
+ * This represents the authority information access extension
+ * as defined in RFC2459.
+ *
+ * id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6)
+ * internet(1) security(5) mechanisms(5)
+ * pkix(7) } }
+ * id-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
+ * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+ * AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription
+ * AccessDescription ::= SEQUENCE {
+ * accessMethod OBJECT IDENTIFIER,
+ * accessLocation GeneralName
+ * }
+ * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+ * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+ * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+ *
+ * Need to make sure the following is added to CMS.cfg:
+ * oidmap.auth_info_access.class=com.netscape.certsrv.cert.AuthInfoAccessExtension
+ * oidmap.auth_info_access.oid=1.3.6.1.5.5.7.1.1
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class AuthInfoAccessExtension extends Extension implements CertAttrSet {
+ private static final long serialVersionUID = 7373316523212538446L;
+ public static final String NAME = "AuthInfoAccessExtension";
+ public static final String NAME2 = "AuthorityInformationAccess";
+
+ public static final int OID_OCSP[] = { 1, 3, 6, 1, 5, 5, 7, 48, 1 };
+ public static final ObjectIdentifier METHOD_OCSP = new
+ ObjectIdentifier(OID_OCSP);
+
+ public static final int OID_CA_ISSUERS[] = { 1, 3, 6, 1, 5, 5, 7, 48, 2 };
+ public static final ObjectIdentifier METHOD_CA_ISSUERS = new
+ ObjectIdentifier(OID_CA_ISSUERS);
+
+ public static final int OID[] = { 1, 3, 6, 1, 5, 5, 7, 1, 1 };
+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID);
+
+ private Vector<AccessDescription> mDesc = new Vector<AccessDescription>();
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public AuthInfoAccessExtension(boolean critical) {
+ this.extensionId = ID;
+ this.critical = critical;
+ this.extensionValue = null; // build this when encodeThis() is called
+ }
+
+ public AuthInfoAccessExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = ID;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+ decodeThis();
+ }
+
+ /**
+ * Sets extension attribute.
+ */
+ public void set(String name, Object obj) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Retrieves extension attribute.
+ */
+ public Object get(String name) throws CertificateException {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Deletes attribute.
+ */
+ public void delete(String name) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Decodes this extension.
+ */
+ public void decode(InputStream in) throws IOException {
+ // NOT USED
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Adds Access Description.
+ */
+ public void addAccessDescription(
+ ObjectIdentifier method,
+ GeneralName gn) {
+ clearValue();
+ mDesc.addElement(new AccessDescription(method, gn));
+ }
+
+ public AccessDescription getAccessDescription(int pos) {
+ return mDesc.elementAt(pos);
+ }
+
+ /**
+ * Returns the number of access description.
+ */
+ public int numberOfAccessDescription() {
+ return mDesc.size();
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of AuthInfoAccess extension");
+ }
+ while (val.data.available() != 0) {
+ DerValue seq = val.data.getDerValue();
+ ObjectIdentifier method = seq.data.getDerValue().getOID();
+ GeneralName gn = new GeneralName(seq.data.getDerValue());
+
+ addAccessDescription(method, gn);
+ }
+ }
+
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < mDesc.size(); i++) {
+ DerOutputStream tmp0 = new DerOutputStream();
+ AccessDescription ad = mDesc.elementAt(i);
+
+ tmp0.putOID(ad.getMethod());
+ ad.getLocation().encode(tmp0);
+ tmp.write(DerValue.tag_Sequence, tmp0);
+ }
+ seq.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Returns a printable representation of the AuthInfoAccess.
+ */
+ public String toString() {
+ String s = super.toString() + "AuthInfoAccess [\n";
+
+ for (int i = 0; i < mDesc.size(); i++) {
+ AccessDescription ad = mDesc.elementAt(i);
+
+ s += "(" + i + ")";
+ s += " ";
+ s += ad.getMethod().toString() + " " + ad.getLocation().toString();
+ }
+ return (s + "]\n");
+ }
+
+ public static void main(String[] argv) {
+ AuthInfoAccessExtension aia = new AuthInfoAccessExtension(false);
+ GeneralName ocspName = new GeneralName(new
+ URIName("http://ocsp.netscape.com"));
+
+ aia.addAccessDescription(METHOD_OCSP, ocspName);
+ GeneralName caIssuersName = new GeneralName(new
+ URIName("http://ocsp.netscape.com"));
+
+ aia.addAccessDescription(METHOD_CA_ISSUERS, caIssuersName);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ try {
+ aia.encode(os);
+
+ System.out.println(Utils.base64encode(os.toByteArray()));
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ }
+
+ try {
+ // test serialization
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+ oos.writeObject(aia);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(
+ bos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bis);
+ AuthInfoAccessExtension clone = (AuthInfoAccessExtension)
+ ois.readObject();
+
+ System.out.println(clone);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/CertInfo.java b/base/util/src/netscape/security/extensions/CertInfo.java
new file mode 100644
index 000000000..ab88ec8ab
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/CertInfo.java
@@ -0,0 +1,120 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Date;
+
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.CertificateAlgorithmId;
+import netscape.security.x509.CertificateIssuerName;
+import netscape.security.x509.CertificateSerialNumber;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.CertificateValidity;
+import netscape.security.x509.CertificateVersion;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertInfo;
+
+/**
+ * Extends X509CertInfo class so that minimal fields are initialized at
+ * creation time so an object of this type is always serializable.
+ */
+public class CertInfo extends X509CertInfo {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2883888348288591989L;
+ public static final CertificateSubjectName SERIALIZE_SUBJECT;
+ public static final CertificateIssuerName SERIALIZE_ISSUER;
+ public static final CertificateValidity SERIALIZE_VALIDITY;
+ public static final CertificateSerialNumber SERIALIZE_SERIALNO;
+ public static final CertificateAlgorithmId SERIALIZE_ALGOR;
+ public static final CertificateVersion FORCE_VERSION_3;
+
+ static {
+ try {
+ // force version 3
+ FORCE_VERSION_3 =
+ new CertificateVersion(CertificateVersion.V3);
+ SERIALIZE_SUBJECT =
+ new CertificateSubjectName(
+ new X500Name("cn=uninitialized"));
+ SERIALIZE_ISSUER =
+ new CertificateIssuerName(
+ new X500Name("cn=uninitialized"));
+ SERIALIZE_VALIDITY =
+ new CertificateValidity(new Date(0), new Date(0));
+ SERIALIZE_SERIALNO =
+ new CertificateSerialNumber(new BigInteger("0"));
+ SERIALIZE_ALGOR =
+ new CertificateAlgorithmId(
+ AlgorithmId.getAlgorithmId("MD5withRSA"));
+ } catch (IOException e) {
+ // should never happen. If does, system is hosed.
+ System.out.println("**** Impossible Error encountered ****");
+ throw new RuntimeException(e.toString());
+ } catch (NoSuchAlgorithmException e) {
+ // should never happen. If does, system is hosed.
+ System.out.println("**** Impossible Error encountered ****");
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Initializes most fields required by der encoding so object will
+ * serialize properly.
+ */
+ // XXX should write a class to use something else for serialization
+ // but this is faster and done now for the time crunch.
+ public CertInfo() {
+ super();
+ makeSerializable(this);
+ }
+
+ public static void makeSerializable(X509CertInfo certinfo) {
+ try {
+ // force version 3.
+ certinfo.set(X509CertInfo.VERSION, FORCE_VERSION_3);
+
+ if (certinfo.get(X509CertInfo.SERIAL_NUMBER) == null) {
+ certinfo.set(X509CertInfo.SERIAL_NUMBER, SERIALIZE_SERIALNO);
+ }
+ if (certinfo.get(X509CertInfo.ALGORITHM_ID) == null) {
+ certinfo.set(X509CertInfo.ALGORITHM_ID, SERIALIZE_ALGOR);
+ }
+ if (certinfo.get(X509CertInfo.ISSUER) == null) {
+ certinfo.set(X509CertInfo.ISSUER, SERIALIZE_ISSUER);
+ }
+ if (certinfo.get(X509CertInfo.VALIDITY) == null) {
+ certinfo.set(X509CertInfo.VALIDITY, SERIALIZE_VALIDITY);
+ }
+ // set subject name anyway - it'll get overwritten.
+ if (certinfo.get(X509CertInfo.SUBJECT) == null) {
+ certinfo.set(X509CertInfo.SUBJECT, SERIALIZE_SUBJECT);
+ }
+ // key is set later in the request.
+ } // these exceptions shouldn't happen here unless the
+ // whole process is hosed.
+ catch (CertificateException e) {
+ } catch (IOException e) {
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/CertificateRenewalWindowExtension.java b/base/util/src/netscape/security/extensions/CertificateRenewalWindowExtension.java
new file mode 100644
index 000000000..018fd71c8
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/CertificateRenewalWindowExtension.java
@@ -0,0 +1,190 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Date;
+import java.util.Enumeration;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+
+/**
+ * This represents the CertificateRenewalWindow extension
+ * as defined in draft-thayes-cert-renewal-00
+ *
+ * CertificateRenewalWindow ::= SEQUENCE {
+ * beginTime GeneralizedTime,
+ * endTime GeneralizedTime OPTIONAL }
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class CertificateRenewalWindowExtension extends Extension
+ implements CertAttrSet {
+ private static final long serialVersionUID = 4470220533545299271L;
+ public static final String NAME = "CertificateRenewalWindow";
+ public static final int OID[] = { 2, 16, 840, 1, 113730, 1, 15 };
+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID);
+
+ private Date mBeginTime = null;
+ private Date mEndTime = null; // optional
+
+ public CertificateRenewalWindowExtension(boolean critical, Date beginTime,
+ Date endTime) throws IOException {
+ this.extensionId = ID;
+ this.critical = critical;
+ mBeginTime = beginTime;
+ mEndTime = endTime;
+ encodeThis();
+ }
+
+ public CertificateRenewalWindowExtension(boolean critical) {
+ this.extensionId = ID;
+ this.critical = critical;
+ this.extensionValue = null; // build this when encodeThis() is called
+ }
+
+ public CertificateRenewalWindowExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = ID;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+ decodeThis();
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Sets extension attribute.
+ */
+ public void set(String name, Object obj) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Retrieves extension attribute.
+ */
+ public Object get(String name) throws CertificateException {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Deletes attribute.
+ */
+ public void delete(String name) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Decodes this extension.
+ */
+ public void decode(InputStream in) throws IOException {
+ // NOT USED
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ // NOT USED
+ return null;
+ }
+
+ public Date getBeginTime() {
+ return mBeginTime;
+ }
+
+ public Date getEndTime() {
+ return mEndTime;
+ }
+
+ public void setBeginTime(Date d) {
+ mBeginTime = d;
+ }
+
+ public void setEndTime(Date d) {
+ mEndTime = d;
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of CertificateWindow extension");
+ }
+ while (val.data.available() != 0) {
+ if (mBeginTime == null) {
+ mBeginTime = val.data.getGeneralizedTime();
+ } else {
+ mEndTime = val.data.getGeneralizedTime();
+ }
+ }
+ }
+
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ tmp.putGeneralizedTime(mBeginTime);
+ if (mEndTime != null) {
+ tmp.putGeneralizedTime(mEndTime);
+ }
+ seq.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Returns a printable representation of the CertificateRenewalWindow.
+ */
+ public String toString() {
+ String s = super.toString() + "CertificateRenewalWindow [\n";
+
+ s += "BeginTime: " + mBeginTime + "\n";
+ if (mEndTime != null) {
+ s += "EndTime: " + mEndTime;
+ }
+ return (s + "]\n");
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/CertificateScopeEntry.java b/base/util/src/netscape/security/extensions/CertificateScopeEntry.java
new file mode 100644
index 000000000..527093ccf
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/CertificateScopeEntry.java
@@ -0,0 +1,103 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.GeneralName;
+
+/**
+ * This represents the CertificateScopeOfUse extension
+ * as defined in draft-thayes-cert-scope-00
+ *
+ * CertificateScopeEntry ::= SEQUENCE {
+ * name GeneralName, -- pattern, as for NameConstraints
+ * portNumber INTEGER OPTIONAL
+ * }
+ * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class CertificateScopeEntry {
+ private GeneralName mGn = null;
+ private BigInt mPort = null;
+
+ /**
+ * Constructs scope with der value.
+ */
+ public CertificateScopeEntry(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for PolicyQualifierInfo.");
+ }
+ DerValue gn = val.data.getDerValue();
+
+ mGn = new GeneralName(gn);
+ if (val.data.available() != 0) {
+ mPort = val.data.getInteger();
+ }
+ }
+
+ /**
+ * Constructs scope wit
+ */
+ public CertificateScopeEntry(GeneralName gn, BigInt port) {
+ mGn = gn;
+ mPort = port; // optional
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ mGn.encode(tmp);
+ if (mPort != null) {
+ tmp.putInteger(mPort);
+ }
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /**
+ * Returns a GeneralName
+ */
+ public GeneralName getGeneralName() {
+ return mGn;
+ }
+
+ /**
+ * Returns a port
+ */
+ public BigInt getPort() {
+ return mPort;
+ }
+
+ /**
+ * Returns a printable representation of the CertificateRenewalWindow.
+ */
+ public String toString() {
+ String s = super.toString() + "CertificateScopeEntry [\n";
+
+ s += "GeneralName: " + mGn;
+ if (mPort != null) {
+ s += "PortNumber: " + mPort;
+ }
+ return (s + "]\n");
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/CertificateScopeOfUseExtension.java b/base/util/src/netscape/security/extensions/CertificateScopeOfUseExtension.java
new file mode 100644
index 000000000..16641f36b
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/CertificateScopeOfUseExtension.java
@@ -0,0 +1,199 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.OIDMap;
+
+/**
+ * This represents the CertificateScopeOfUse extension
+ * as defined in draft-thayes-cert-scope-00
+ *
+ * CertificateScopeEntry ::= SEQUENCE {
+ * name GeneralName, -- pattern, as for NameConstraints
+ * portNumber INTEGER OPTIONAL
+ * }
+ * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class CertificateScopeOfUseExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2143292831971567770L;
+ public static final String NAME = "CertificateScopeOfUse";
+ public static final int OID[] = { 2, 16, 840, 1, 113730, 1, 17 };
+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID);
+
+ private Vector<CertificateScopeEntry> mEntries = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(CertificateScopeOfUseExtension.class.getName(),
+ ID.toString(), NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ public CertificateScopeOfUseExtension(boolean critical, Vector<CertificateScopeEntry> scopeEntries)
+ throws IOException {
+ this.extensionId = ID;
+ this.critical = critical;
+ this.extensionValue = null; // build this when encodeThis() is called
+ mEntries = scopeEntries;
+ encodeThis();
+ }
+
+ public CertificateScopeOfUseExtension(boolean critical) {
+ this.extensionId = ID;
+ this.critical = critical;
+ this.extensionValue = null; // build this when encodeThis() is called
+ }
+
+ public CertificateScopeOfUseExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = ID;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+ decodeThis();
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public Vector<CertificateScopeEntry> getCertificateScopeEntries() {
+ return mEntries;
+ }
+
+ /**
+ * Sets extension attribute.
+ */
+ public void set(String name, Object obj) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Retrieves extension attribute.
+ */
+ public Object get(String name) throws CertificateException {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Deletes attribute.
+ */
+ public void delete(String name) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Decodes this extension.
+ */
+ public void decode(InputStream in) throws IOException {
+ // NOT USED
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ // NOT USED
+ return null;
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of CertificateWindow extension");
+ }
+ mEntries = new Vector<CertificateScopeEntry>();
+ while (val.data.available() != 0) {
+ mEntries.addElement(new CertificateScopeEntry(
+ val.data.getDerValue()));
+ }
+ }
+
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (mEntries == null)
+ throw new IOException("Invalid Scope Entries");
+
+ for (int i = 0; i < mEntries.size(); i++) {
+ CertificateScopeEntry se = (CertificateScopeEntry)
+ mEntries.elementAt(i);
+
+ se.encode(tmp);
+ }
+
+ seq.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Returns a printable representation of the CertificateRenewalWindow.
+ */
+ public String toString() {
+ String s = super.toString() + "CertificateUseOfScope [\n";
+
+ if (mEntries != null) {
+ for (int i = 0; i < mEntries.size(); i++) {
+ CertificateScopeEntry se = (CertificateScopeEntry)
+ mEntries.elementAt(i);
+
+ s += se.toString();
+ }
+ }
+ return (s + "]\n");
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/ExtendedKeyUsageExtension.java b/base/util/src/netscape/security/extensions/ExtendedKeyUsageExtension.java
new file mode 100644
index 000000000..939da036f
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/ExtendedKeyUsageExtension.java
@@ -0,0 +1,226 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.OIDMap;
+
+/**
+ * This represents the extended key usage extension.
+ */
+public class ExtendedKeyUsageExtension extends Extension implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 765403075764697489L;
+ public static final String OID = "2.5.29.37";
+ public static final String NAME = OIDMap.EXT_KEY_USAGE_NAME;
+ public static final String OID_OCSPSigning = "1.3.6.1.5.5.7.3.9";
+ public static final String OID_CODESigning = "1.3.6.1.5.5.7.3.3";
+
+ public static final int OID_OCSP_SIGNING_STR[] =
+ { 1, 3, 6, 1, 5, 5, 7, 3, 9 };
+ public static final ObjectIdentifier OID_OCSP_SIGNING = new
+ ObjectIdentifier(OID_OCSP_SIGNING_STR);
+
+ public static final int OID_CODE_SIGNING_STR[] =
+ { 1, 3, 6, 1, 5, 5, 7, 3, 3 };
+ public static final ObjectIdentifier OID_CODE_SIGNING = new
+ ObjectIdentifier(OID_OCSP_SIGNING_STR);
+
+ private Vector<ObjectIdentifier> oidSet = null;
+ private byte mCached[] = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(ExtendedKeyUsageExtension.class.getName(),
+ OID, ExtendedKeyUsageExtension.NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ public ExtendedKeyUsageExtension() {
+ this(false, null);
+ }
+
+ public ExtendedKeyUsageExtension(boolean crit, Vector<ObjectIdentifier> oids) {
+ try {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OID);
+ } catch (IOException e) {
+ // never here
+ }
+ critical = crit;
+ if (oids != null) {
+ oidSet = new Vector<ObjectIdentifier>(oids);
+ } else {
+ oidSet = new Vector<ObjectIdentifier>();
+ }
+ encodeExtValue();
+ }
+
+ public ExtendedKeyUsageExtension(Boolean crit, Object byteVal)
+ throws IOException {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OID);
+ critical = crit.booleanValue();
+ extensionValue = (byte[]) ((byte[]) byteVal).clone();
+ decodeThis();
+ }
+
+ public void setCritical(boolean newValue) {
+ if (critical != newValue) {
+ critical = newValue;
+ mCached = null;
+ }
+ }
+
+ public Enumeration<ObjectIdentifier> getOIDs() {
+ if (oidSet == null)
+ return null;
+ return oidSet.elements();
+ }
+
+ public void deleteAllOIDs() {
+ if (oidSet == null)
+ return;
+ oidSet.clear();
+ }
+
+ public void addOID(ObjectIdentifier oid) {
+ if (oidSet == null) {
+ oidSet = new Vector<ObjectIdentifier>();
+ }
+
+ if (oidSet.contains(oid))
+ return;
+ oidSet.addElement(oid);
+ mCached = null;
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+ if (mCached == null) {
+ encodeExtValue();
+ super.encode(out);
+ mCached = out.toByteArray();
+ }
+ }
+
+ public String toString() {
+ String presentation = "oid=" + ExtendedKeyUsageExtension.OID + " ";
+
+ if (critical) {
+ presentation += "critical=true";
+ }
+ if (extensionValue != null) {
+ String extByteValue = new String(" val=");
+
+ for (int i = 0; i < extensionValue.length; i++) {
+ extByteValue += (extensionValue[i] + " ");
+ }
+ presentation += extByteValue;
+ }
+ return presentation;
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ }
+
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ if (mCached == null) {
+ DerOutputStream temp = new DerOutputStream();
+
+ encode(temp);
+ }
+ out.write(mCached);
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ public Object get(String name) throws CertificateException, IOException {
+ // NOT USED
+ return null;
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of AuthInfoAccess extension");
+ }
+ if (oidSet == null)
+ oidSet = new Vector<ObjectIdentifier>();
+ while (val.data.available() != 0) {
+ DerValue oidVal = val.data.getDerValue();
+
+ oidSet.addElement(oidVal.getOID());
+ }
+ }
+
+ private void encodeExtValue() {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream temp = new DerOutputStream();
+
+ if (!oidSet.isEmpty()) {
+ Enumeration<ObjectIdentifier> oidList = oidSet.elements();
+
+ try {
+ while (oidList.hasMoreElements()) {
+ temp.putOID((ObjectIdentifier) oidList.nextElement());
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ try {
+ out.write(DerValue.tag_Sequence, temp);
+ } catch (IOException ex) {
+ }
+
+ extensionValue = out.toByteArray();
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/GenericASN1Extension.java b/base/util/src/netscape/security/extensions/GenericASN1Extension.java
new file mode 100644
index 000000000..ff1ea7173
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/GenericASN1Extension.java
@@ -0,0 +1,448 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.OIDMap;
+
+/**
+ * Represent the AsnInteger Extension.
+ */
+public class GenericASN1Extension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8047548816784949009L;
+
+ protected static final int MAX_ATTR = 10;
+
+ protected static final String PROP_CRITICAL =
+ "critical";
+ protected static final String PROP_NAME =
+ "name";
+ protected static final String PROP_OID =
+ "oid";
+ protected static final String PROP_PATTERN =
+ "pattern";
+ protected static final String PROP_ATTRIBUTE =
+ "attribute";
+ protected static final String PROP_TYPE =
+ "type";
+ protected static final String PROP_SOURCE =
+ "source";
+ protected static final String PROP_VALUE =
+ "value";
+ protected static final String PROP_PREDICATE =
+ "predicate";
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ private String name;
+ public String OID = null;
+ public static Hashtable<String, String> mConfig = null;
+ public String pattern = null;
+ private int index = 0;
+
+ // Encode this value
+ private void encodeThis()
+ throws IOException, ParseException {
+ this.extensionValue = encodePattern();
+ }
+
+ // Encode pattern
+ private byte[] encodePattern()
+ throws IOException, ParseException {
+ DerOutputStream os = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+ String type = null;
+ String value = null;
+ String source = null;
+ while (index < pattern.length()) {
+ char ch = pattern.charAt(index);
+ switch (ch) {
+ case '{':
+ index++;
+ byte[] buff = encodePattern();
+ tmp.putDerValue(new DerValue(buff));
+ break;
+ case '}':
+ os.write(DerValue.tag_Sequence, tmp);
+ return os.toByteArray();
+ default:
+ type = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_TYPE);
+ if (type.equalsIgnoreCase("integer")) {
+ int num = Integer.parseInt((String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE));
+ PutInteger(tmp, num);
+ } else if (type.equalsIgnoreCase("ia5string")) {
+ source = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE);
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ if (source.equalsIgnoreCase("file"))
+ PutIA5String(tmp, getFromFile(value));
+ else
+ PutIA5String(tmp, value);
+ } else if (type.equalsIgnoreCase("octetstring")) {
+ source = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE);
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ // It should be colon seperated ASCII Hexdecimal String
+ if (source.equalsIgnoreCase("file"))
+ PutOctetString(tmp, getFromFile(value));
+ else
+ PutOctetString(tmp, value);
+ } else if (type.equalsIgnoreCase("bmpstring")) {
+ source = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE);
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ if (source.equalsIgnoreCase("file"))
+ PutBMPString(tmp, getFromFile(value));
+ else
+ PutBMPString(tmp, value);
+ } else if (type.equalsIgnoreCase("printablestring")) {
+ source = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE);
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ if (source.equalsIgnoreCase("file"))
+ PutPrintableString(tmp, getFromFile(value));
+ else
+ PutPrintableString(tmp, value);
+ } else if (type.equalsIgnoreCase("visiblestring")) {
+ source = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE);
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ if (source.equalsIgnoreCase("file"))
+ PutVisibleString(tmp, getFromFile(value));
+ else
+ PutVisibleString(tmp, value);
+ } else if (type.equalsIgnoreCase("utctime")) {
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ PutUTCtime(tmp, value);
+ } else if (type.equalsIgnoreCase("oid")) {
+ value = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ PutOID(tmp, value);
+ } else if (type.equalsIgnoreCase("boolean")) {
+ boolean bool = false;
+ String b = (String) mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE);
+ if (b.equalsIgnoreCase("true"))
+ bool = true;
+ else
+ bool = false;
+ PutBoolean(tmp, bool);
+ } else if (type.equalsIgnoreCase("null")) {
+ tmp.putNull();
+ } else {
+ throw new ParseException("Unknown Attribute Type", 0);
+ }
+ }
+ index++;
+ }
+
+ return tmp.toByteArray();
+ }
+
+ /**
+ * Create a GenericASN1Extension with the value and oid.
+ * The criticality is set to false.
+ *
+ * @param the values to be set for the extension.
+ */
+ public GenericASN1Extension(String name, String oid, String pattern, boolean critical,
+ Hashtable<String, String> config)
+ throws IOException, ParseException {
+ ObjectIdentifier tmpid = new ObjectIdentifier(oid);
+ this.name = name;
+ OID = oid;
+ mConfig = config;
+ this.pattern = pattern;
+
+ try {
+ if (OIDMap.getName(tmpid) == null)
+ OIDMap.addAttribute("netscape.security.x509.GenericASN1Extension", oid, name);
+ } catch (CertificateException e) {
+ }
+
+ this.extensionId = tmpid;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create a GenericASN1Extension with the value and oid.
+ * The criticality is set to false.
+ *
+ * @param the values to be set for the extension.
+ */
+ public GenericASN1Extension(Hashtable<String, String> config)
+ throws IOException, ParseException {
+ mConfig = config;
+ ObjectIdentifier tmpid = new ObjectIdentifier((String) mConfig.get(PROP_OID));
+ name = (String) mConfig.get(PROP_NAME);
+ OID = (String) mConfig.get(PROP_OID);
+ pattern = (String) mConfig.get(PROP_PATTERN);
+
+ try {
+ if (OIDMap.getName(tmpid) == null)
+ OIDMap.addAttribute("GenericASN1Extension", OID, name);
+ } catch (CertificateException e) {
+ }
+
+ this.extensionId = tmpid;
+ this.critical = false;
+ String b = (String) mConfig.get(PROP_CRITICAL);
+ if (b.equalsIgnoreCase("true"))
+ this.critical = true;
+ else
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public GenericASN1Extension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = new ObjectIdentifier(OID);
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ return null;
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Returns a printable representation of the GenericASN1Extension.
+ */
+ public String toString() {
+ return (null);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out)
+ throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ try {
+ if (this.extensionValue == null) {
+ this.extensionId = new ObjectIdentifier(OID);
+ this.critical = true;
+ encodeThis();
+ }
+ } catch (ParseException e) {
+ }
+
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the name of this attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the OID of this attribute.
+ */
+ public String getOID() {
+ return OID;
+ }
+
+ /**
+ * Set the OID of this attribute.
+ */
+ public void setOID(String oid) {
+ OID = oid;
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement("octet");
+
+ return (elements.elements());
+ }
+
+ private void PutInteger(DerOutputStream os, int number)
+ throws IOException, ParseException {
+ os.putInteger(new BigInt(number));
+ return;
+ }
+
+ private void PutIA5String(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ os.putIA5String(value);
+ return;
+ }
+
+ private void PutOctetString(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ StringTokenizer token = new StringTokenizer(value, ":");
+ byte[] octets = new byte[token.countTokens()];
+ for (int i = 0; token.hasMoreElements(); i++) {
+ String num = (String) token.nextElement();
+ octets[i] = (byte) Integer.parseInt(num, 16);
+ }
+
+ os.putOctetString(octets);
+ return;
+ }
+
+ private void PutBMPString(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ os.putBMPString(value);
+ return;
+ }
+
+ private void PutPrintableString(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ os.putPrintableString(value);
+ return;
+ }
+
+ private void PutVisibleString(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ os.putVisibleString(value);
+ return;
+ }
+
+ private void PutUTCtime(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
+ os.putUTCTime(df.parse(value));
+ return;
+ }
+
+ private void PutOID(DerOutputStream os, String value)
+ throws IOException, ParseException {
+ os.putOID(new ObjectIdentifier(value));
+ return;
+ }
+
+ private void PutBoolean(DerOutputStream os, boolean value)
+ throws IOException, ParseException {
+ os.putBoolean(value);
+ return;
+ }
+
+ private String getFromFile(String fname) throws IOException {
+ String s = null;
+ byte[] buff = null;
+ int i = 0;
+ int j = 0;
+ if ((fname == null) || (fname.equals(""))) {
+ throw new IOException("File name is not provided.");
+ }
+
+ FileInputStream fis = new FileInputStream(fname);
+ int n = 0;
+ while ((n = fis.available()) > 0) {
+ buff = new byte[n];
+ int result = fis.read(buff);
+ if (result == -1)
+ break;
+ s = new String(buff);
+ }
+
+ for (i = 0, j = 0; j < s.length(); j++) {
+ int ch = (int) s.charAt(j);
+ if (ch == 10 || ch == 13 || ch == 9)
+ continue;
+ i++;
+ }
+ buff = new byte[i];
+ for (i = 0, j = 0; j < s.length(); j++) {
+ int ch = (int) s.charAt(j);
+ if (ch == 10 || ch == 13 || ch == 9)
+ continue;
+ buff[i++] = (byte) ch;
+ }
+
+ s = new String(buff);
+
+ return s;
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/InhibitAnyPolicyExtension.java b/base/util/src/netscape/security/extensions/InhibitAnyPolicyExtension.java
new file mode 100644
index 000000000..81b8cf5b5
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/InhibitAnyPolicyExtension.java
@@ -0,0 +1,179 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.OIDMap;
+
+/**
+ * RFC3280:
+ *
+ * id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 }
+ *
+ * InhibitAnyPolicy ::= SkipCerts
+ *
+ * SkipCerts ::= INTEGER (0..MAX)
+ */
+public class InhibitAnyPolicyExtension
+ extends Extension implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8963439897419343166L;
+ public static final String OID = "2.5.29.54";
+ public static final String NAME = OIDMap.EXT_INHIBIT_ANY_POLICY_NAME;
+
+ private BigInt mSkipCerts = new BigInt(-1);
+
+ static {
+ try {
+ OIDMap.addAttribute(InhibitAnyPolicyExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ public InhibitAnyPolicyExtension() {
+ this(false, null);
+ }
+
+ public InhibitAnyPolicyExtension(boolean crit, BigInt skipCerts) {
+ try {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OID);
+ } catch (IOException e) {
+ // never here
+ }
+ critical = crit;
+ mSkipCerts = skipCerts;
+ encodeExtValue();
+ }
+
+ public InhibitAnyPolicyExtension(Boolean crit, Object value)
+ throws IOException {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OID);
+ critical = crit.booleanValue();
+ //extensionValue = (byte[]) ((byte[]) byteVal).clone();
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+
+ extensionValue = extValue;
+ decodeThis();
+ }
+
+ public void setCritical(boolean newValue) {
+ if (critical != newValue) {
+ critical = newValue;
+ }
+ }
+
+ public BigInt getSkipCerts() {
+ return mSkipCerts;
+ }
+
+ public String toString() {
+ String presentation = "ObjectId: " + OID + " ";
+
+ if (critical) {
+ presentation += "Criticality=true";
+ } else {
+ presentation += "Criticality=false";
+ }
+ if (extensionValue != null) {
+ String extByteValue = new String(" skipCerts=" + mSkipCerts);
+
+ presentation += extByteValue;
+ }
+ return presentation;
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ public Object get(String name) throws CertificateException, IOException {
+ // NOT USED
+ return null;
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ mSkipCerts = val.getInteger();
+ }
+
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ try {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OID);
+ } catch (IOException e) {
+ // never here
+ }
+ DerOutputStream os = new DerOutputStream();
+ os.putInteger(mSkipCerts);
+ this.extensionValue = os.toByteArray();
+ }
+
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ private void encodeExtValue() {
+ DerOutputStream out = new DerOutputStream();
+ try {
+ out.putInteger(mSkipCerts);
+ } catch (IOException e) {
+ }
+ extensionValue = out.toByteArray();
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/KerberosName.java b/base/util/src/netscape/security/extensions/KerberosName.java
new file mode 100644
index 000000000..0a6a6e213
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/KerberosName.java
@@ -0,0 +1,135 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * This represents a KerberosName as defined in
+ * RFC 1510.
+ *
+ * KerberosName ::= SEQUENCE {
+ * realm [0] Realm,
+ * principalName [1] CertPrincipalName -- defined above
+ * }
+ *
+ * CertPrincipalName ::= SEQUENCE {
+ * name-type[0] INTEGER,
+ * name-string[1] SEQUENCE OF UTF8String
+ * }
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KerberosName {
+
+ public static final int OID[] = { 1, 3, 6, 1, 5, 2, 2 };
+ public static final ObjectIdentifier KRB5_PRINCIPAL_NAME = new
+ ObjectIdentifier(OID);
+
+ private String m_realm = null;
+ private int m_name_type = 0;
+ private Vector<String> m_name_strings = null;
+
+ public KerberosName(String realm, int name_type, Vector<String> name_strings) {
+ m_realm = realm;
+ m_name_type = name_type;
+ m_name_strings = name_strings;
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream realm = new DerOutputStream();
+ realm.putGeneralString(m_realm);
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) 0), realm);
+
+ DerOutputStream seq1 = new DerOutputStream();
+ DerOutputStream tmp1 = new DerOutputStream();
+ DerOutputStream name_type = new DerOutputStream();
+ name_type.putInteger(new BigInt(m_name_type));
+ tmp1.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) 0), name_type);
+
+ DerOutputStream name_strings = new DerOutputStream();
+ DerOutputStream name_string = new DerOutputStream();
+ for (int i = 0; i < m_name_strings.size(); i++) {
+ name_string.putGeneralString((String) m_name_strings.elementAt(i));
+ }
+ name_strings.write(DerValue.tag_SequenceOf, name_string);
+ tmp1.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) 1), name_strings);
+ seq1.write(DerValue.tag_Sequence, tmp1);
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) 1), seq1);
+
+ seq.write(DerValue.tag_Sequence, tmp);
+ out.write(seq.toByteArray());
+ }
+
+ public byte[] toByteArray() throws IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ encode(bos);
+ return bos.toByteArray();
+ }
+
+ public String toString() {
+ String strings = null;
+ for (int i = 0; i < m_name_strings.size(); i++) {
+ if (strings == null) {
+ strings = (String) m_name_strings.elementAt(i);
+ } else {
+ strings += ",";
+ strings += (String) m_name_strings.elementAt(i);
+ }
+ }
+ return "Realm: " + m_realm + " Name Type: " + m_name_type + " Name String(s):" + strings;
+ }
+
+ public static void main(String[] argv) {
+ Vector<String> strings = new Vector<String>();
+ strings.addElement("name");
+ KerberosName k = new KerberosName("realm", 0, strings);
+
+ System.out.println(k.toString());
+ try {
+ FileOutputStream os = new FileOutputStream("/tmp/out.der");
+ k.encode(os);
+ os.close();
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/NSCertTypeExtension.java b/base/util/src/netscape/security/extensions/NSCertTypeExtension.java
new file mode 100644
index 000000000..04b3038e5
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/NSCertTypeExtension.java
@@ -0,0 +1,377 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+
+/**
+ * NSCertTypeExtension
+ * Represents Netscape Certificate Type Extension
+ *
+ * <p>
+ * This deprecated extension, if present, defines both the purpose (e.g., encipherment, signature, certificate signing)
+ * and the application (e.g., SSL, S/Mime or Object Signing of the key contained in the certificate.
+ *
+ * @author galperin
+ * @version $Revision$, $Date$
+ */
+public class NSCertTypeExtension extends Extension implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1856407688086284397L;
+
+ // The object identifiers
+ private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 };
+
+ /**
+ * Identifies the particular public key used to sign the certificate.
+ */
+ public static final ObjectIdentifier CertType_Id = new
+ ObjectIdentifier(CertType_data);
+
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "NSCertType";
+ public static final String SSL_CLIENT = "ssl_client";
+ public static final String SSL_SERVER = "ssl_server";
+ public static final String EMAIL = "email";
+ public static final String OBJECT_SIGNING = "object_signing";
+ public static final String SSL_CA = "ssl_ca";
+ public static final String EMAIL_CA = "email_ca";
+ public static final String OBJECT_SIGNING_CA = "object_signing_ca";
+
+ /**
+ * Attribute names.
+ */
+ public static final int SSL_CLIENT_BIT = 0;
+ public static final int SSL_SERVER_BIT = 1;
+ public static final int EMAIL_BIT = 2;
+ public static final int OBJECT_SIGNING_BIT = 3;
+ // 4 is reserved.
+ public static final int SSL_CA_BIT = 5;
+ public static final int EMAIL_CA_BIT = 6;
+ public static final int OBJECT_SIGNING_CA_BIT = 7;
+
+ public static final int NBITS = 8;
+
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.NSCertType";
+
+ // Private data members
+ private byte[] mBitString;
+
+ private static class MapEntry {
+ String mName;
+ int mPosition;
+
+ MapEntry(String name, int position) {
+ mName = name;
+ mPosition = position;
+ }
+ }
+
+ private static MapEntry[] mMapData =
+ {
+ new MapEntry(SSL_CLIENT, 0),
+ new MapEntry(SSL_SERVER, 1),
+ new MapEntry(EMAIL, 2),
+ new MapEntry(OBJECT_SIGNING, 3),
+ // note that bit 4 is reserved
+ new MapEntry(SSL_CA, 5),
+ new MapEntry(EMAIL_CA, 6),
+ new MapEntry(OBJECT_SIGNING_CA, 7),
+ };
+
+ private static Vector<String> mAttributeNames = new Vector<String>();
+
+ static {
+ for (int i = 0; i < mMapData.length; ++i) {
+ mAttributeNames.addElement(mMapData[i].mName);
+ }
+ }
+
+ private static int getPosition(String name) throws CertificateException {
+ for (int i = 0; i < mMapData.length; ++i) {
+ if (name.equalsIgnoreCase(mMapData[i].mName))
+ return mMapData[i].mPosition;
+ }
+ throw new CertificateException("Attribute name [" + name
+ + "] not recognized by"
+ + " CertAttrSet:NSCertType.");
+ }
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+
+ os.putUnalignedBitString(mBitString);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Check if bit is set.
+ *
+ * @param position the position in the bit string to check.
+ */
+ public boolean isSet(int position) {
+ int index = position / 8;
+ byte pos = (byte) (1 << (7 - (position % 8)));
+
+ if (mBitString.length <= index)
+ return false;
+ return ((mBitString[index] & pos) != 0);
+ }
+
+ /**
+ * Set the bit at the specified position.
+ */
+ public void set(int position, boolean val) {
+ int index = position / 8;
+ byte pos = (byte) (1 << (7 - (position % 8)));
+
+ if (index >= mBitString.length) {
+ byte[] tmp = new byte[index + 1];
+
+ System.arraycopy(mBitString, 0, tmp, 0, mBitString.length);
+ mBitString = tmp;
+ }
+ if (val) {
+ mBitString[index] |= pos;
+ } else {
+ mBitString[index] &= ~pos;
+ }
+ }
+
+ /**
+ * Create NSCertTypeExtension from boolean array.
+ * The criticality is set to false.
+ */
+ public NSCertTypeExtension(boolean critical, boolean[] bits) {
+ this.extensionId = CertType_Id;
+ this.critical = critical;
+ this.mBitString = new byte[0];
+
+ for (int i = 0; i < bits.length && i < 8; i++) {
+ set(i, bits[i]);
+ }
+ }
+
+ public NSCertTypeExtension(boolean[] bits) {
+ this.extensionId = CertType_Id;
+ this.critical = false;
+ this.mBitString = new byte[0];
+
+ for (int i = 0; i < bits.length && i < 8; i++) {
+ set(i, bits[i]);
+ }
+ }
+
+ /**
+ * Create a NSCertTypeExtension with the passed bit settings.
+ * The criticality is set to false.
+ *
+ * @param bitString the bits to be set for the extension.
+ */
+ public NSCertTypeExtension(boolean critical, byte[] bitString) throws IOException {
+ this.mBitString = bitString;
+ this.extensionId = CertType_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ public NSCertTypeExtension(byte[] bitString) throws IOException {
+ this.mBitString = bitString;
+ this.extensionId = CertType_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public NSCertTypeExtension(Boolean critical, Object value)
+ throws IOException {
+
+ /**
+ * Debug.trace("NSCertTypeExtension");
+ * this.mBitString = new byte[1];
+ * this.mBitString[0] = (byte)0x00;
+ * return;
+ **/
+
+ this.extensionId = CertType_Id;
+ this.critical = critical.booleanValue();
+ byte[] extValue = (byte[]) ((byte[]) value).clone();
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+
+ this.mBitString = val.getUnalignedBitString().toByteArray();
+ }
+
+ /**
+ * Create a default key usage.
+ */
+ public NSCertTypeExtension() {
+ this.extensionId = CertType_Id;
+ this.critical = false;
+ this.mBitString = new byte[0];
+ try {
+ encodeThis();
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws CertificateException {
+ if (!(obj instanceof Boolean)) {
+ throw new CertificateException("Attribute must be of type Boolean.");
+ }
+ boolean val = ((Boolean) obj).booleanValue();
+
+ set(getPosition(name), val);
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws CertificateException {
+ return new Boolean(isSet(getPosition(name)));
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws CertificateException {
+ set(getPosition(name), false);
+ }
+
+ /**
+ * Returns a printable representation of the NSCertType.
+ */
+ public String toString() {
+ String s = super.toString() + "NSCertType [\n";
+
+ try {
+
+ if (isSet(getPosition(SSL_CLIENT))) {
+ s += " SSL client";
+ }
+ if (isSet(getPosition(SSL_SERVER))) {
+ s += " SSL server";
+ }
+
+ if (isSet(getPosition(EMAIL))) {
+ s += " Email";
+ }
+
+ if (isSet(getPosition(OBJECT_SIGNING))) {
+ s += " Object Signing";
+ }
+
+ if (isSet(getPosition(SSL_CA))) {
+ s += " SSL CA";
+ }
+
+ if (isSet(getPosition(EMAIL_CA))) {
+ s += " Email CA";
+ }
+
+ if (isSet(getPosition(OBJECT_SIGNING_CA))) {
+ s += " Object Signing CA";
+ }
+
+ } catch (Exception e) {
+ // this is reached only if there is a bug
+ throw new IllegalArgumentException(e.getMessage());
+ }
+
+ s += "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ encodeThis();
+ if (this.extensionValue == null) {
+ this.extensionId = CertType_Id;
+ this.critical = true;
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ return mAttributeNames.elements();
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ public static void main(String[] argv) {
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/OCSPNoCheckExtension.java b/base/util/src/netscape/security/extensions/OCSPNoCheckExtension.java
new file mode 100644
index 000000000..28da8085f
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/OCSPNoCheckExtension.java
@@ -0,0 +1,153 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.OIDMap;
+
+/**
+ * This represents the OCSPNoCheck extension.
+ */
+public class OCSPNoCheckExtension extends Extension implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4692759557964594790L;
+ public static final String OID = "1.3.6.1.5.5.7.48.1.5";
+ public static final String NAME = "OCSPNoCheckExtension";
+
+ private byte mCached[] = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(OCSPNoCheckExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ public OCSPNoCheckExtension() {
+ this(Boolean.FALSE);
+ }
+
+ public OCSPNoCheckExtension(Boolean crit) {
+ try {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OCSPNoCheckExtension.OID);
+ } catch (IOException e) {
+ // never here
+ }
+ critical = crit.booleanValue();
+ DerOutputStream tmpD = new DerOutputStream();
+
+ try {
+ tmpD.putNull();
+ } catch (IOException ex) {
+ }
+ extensionValue = tmpD.toByteArray();
+ }
+
+ public OCSPNoCheckExtension(Boolean crit, Object byteVal) {
+ try {
+ extensionId = ObjectIdentifier.getObjectIdentifier(OCSPNoCheckExtension.OID);
+ } catch (IOException e) {
+ // never here
+ }
+ critical = crit.booleanValue();
+ extensionValue = (byte[]) ((byte[]) byteVal).clone();
+ }
+
+ public void setCritical(boolean newValue) {
+ if (critical != newValue) {
+ critical = newValue;
+ mCached = null;
+ }
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+ if (mCached == null) {
+ super.encode(out);
+ mCached = out.toByteArray();
+ }
+ }
+
+ public String toString() {
+ String presentation = "oid=" + OID + " ";
+
+ if (critical) {
+ presentation += "critical=true";
+ }
+ if (extensionValue != null) {
+ String extByteValue = new String(" val=");
+
+ for (int i = 0; i < extensionValue.length; i++) {
+ extByteValue += (extensionValue[i] + " ");
+ }
+ presentation += extByteValue;
+ }
+ return presentation;
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ if (mCached == null) {
+ DerOutputStream temp = new DerOutputStream();
+
+ encode(temp);
+ }
+ out.write(mCached);
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+
+ public Object get(String name) throws CertificateException, IOException {
+ // NOT USED
+ return null;
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ // NOT USED
+ return null;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ // NOT USED
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/PresenceServerExtension.java b/base/util/src/netscape/security/extensions/PresenceServerExtension.java
new file mode 100644
index 000000000..c67fe9965
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/PresenceServerExtension.java
@@ -0,0 +1,321 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+
+public class PresenceServerExtension extends Extension implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6333109673043357921L;
+ private boolean mCritical;
+ private String mOID = null;
+ private int mVersion = 0;
+ private String mStreetAddress = null;
+ private String mTelephoneNumber = null;
+ private String mRFC822Name = null;
+ private String mID = null;
+ private String mHostName = null;
+ private int mPortNumber = 0;
+ private int mMaxUsers = 0;
+ private int mServiceLevel = 0;
+
+ public static final String OID = "2.16.840.1.113730.1.18";
+
+ /*
+ public PresenceServerExtension()
+ {
+ }
+ */
+
+ public PresenceServerExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = new ObjectIdentifier(OID);
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+ decodeThis();
+ }
+
+ public PresenceServerExtension(
+ boolean critical,
+ int version,
+ String streetAddress,
+ String telephoneNumber,
+ String rfc822Name,
+ String ID,
+ String hostName,
+ int portNumber,
+ int maxUsers,
+ int serviceLevel)
+ throws IOException {
+ mCritical = critical;
+ mVersion = version;
+ mStreetAddress = streetAddress;
+ mTelephoneNumber = telephoneNumber;
+ mRFC822Name = rfc822Name;
+ mID = ID;
+ mHostName = hostName;
+ mPortNumber = portNumber;
+ mMaxUsers = maxUsers;
+ mServiceLevel = serviceLevel;
+
+ this.extensionId = new ObjectIdentifier(OID);
+ this.critical = mCritical;
+ encodeThis();
+ }
+
+ public int getVersion() {
+ return mVersion;
+ }
+
+ public String getStreetAddress() {
+ return mStreetAddress;
+ }
+
+ public String getTelephoneNumber() {
+ return mTelephoneNumber;
+ }
+
+ public String getRFC822() {
+ return mRFC822Name;
+ }
+
+ public String getID() {
+ return mID;
+ }
+
+ public String getHostName() {
+ return mHostName;
+ }
+
+ public int getPortNumber() {
+ return mPortNumber;
+ }
+
+ public int getMaxUsers() {
+ return mMaxUsers;
+ }
+
+ public int getServiceLevel() {
+ return mServiceLevel;
+ }
+
+ public void encodeThis() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream temp = new DerOutputStream();
+ temp.putInteger(new BigInt(mVersion));
+ temp.putOctetString(mStreetAddress.getBytes());
+ temp.putOctetString(mTelephoneNumber.getBytes());
+ temp.putOctetString(mRFC822Name.getBytes());
+ temp.putOctetString(mID.getBytes());
+ temp.putOctetString(mHostName.getBytes());
+ temp.putInteger(new BigInt(mPortNumber));
+ temp.putInteger(new BigInt(mMaxUsers));
+ temp.putInteger(new BigInt(mServiceLevel));
+ out.write(DerValue.tag_Sequence, temp);
+ this.extensionValue = out.toByteArray();
+ }
+
+ public void decodeThis() throws IOException {
+ DerInputStream val = new DerInputStream(this.extensionValue);
+ byte data[] = null;
+ DerValue seq[] = val.getSequence(0);
+
+ mVersion = seq[0].getInteger().toInt();
+ data = null;
+ if (seq[1].length() > 0) {
+ data = seq[1].getOctetString();
+ }
+ if (data == null) {
+ mStreetAddress = "";
+ } else {
+ mStreetAddress = new String(data);
+ }
+ data = null;
+ if (seq[2].length() > 0)
+ data = seq[2].getOctetString();
+ if (data == null) {
+ mTelephoneNumber = "";
+ } else {
+ mTelephoneNumber = new String(data);
+ }
+ data = null;
+ if (seq[3].length() > 0)
+ data = seq[3].getOctetString();
+ if (data == null) {
+ mRFC822Name = "";
+ } else {
+ mRFC822Name = new String(data);
+ }
+ data = null;
+ if (seq[4].length() > 0)
+ data = seq[4].getOctetString();
+ if (data == null) {
+ mID = "";
+ } else {
+ mID = new String(data);
+ }
+ data = null;
+ if (seq[5].length() > 0)
+ data = seq[5].getOctetString();
+ if (data == null) {
+ mHostName = "";
+ } else {
+ mHostName = new String(data);
+ }
+ mPortNumber = seq[6].getInteger().toInt();
+ mMaxUsers = seq[7].getInteger().toInt();
+ mServiceLevel = seq[8].getInteger().toInt();
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ }
+
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ DerOutputStream dos = new DerOutputStream();
+ super.encode(dos);
+ out.write(dos.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ return null;
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return "PresenceServerExtension";
+ }
+
+ /**
+ * Set the name of this attribute.
+ */
+ public void setName(String name) {
+ }
+
+ /**
+ * Return the OID of this attribute.
+ */
+ public String getOID() {
+ return OID;
+ }
+
+ /**
+ * Set the OID of this attribute.
+ */
+ public void setOID(String oid) {
+ }
+
+ public static void main(String args[]) throws Exception {
+ /*
+ 0 30 115: SEQUENCE {
+ 2 06 9: OBJECT IDENTIFIER '2 16 840 1 113730 1 100'
+ 13 04 102: OCTET STRING, encapsulates {
+ 15 30 100: SEQUENCE {
+ 17 02 1: INTEGER 0
+ 20 04 31: OCTET STRING
+ : 34 30 31 45 20 4D 69 64 64 6C 65 66 69 65 6C 64
+ : 20 52 64 2E 2C 4D 56 2C 43 41 39 34 30 34 31
+ 53 04 12: OCTET STRING
+ : 36 35 30 2D 31 31 31 2D 31 31 31 31
+ 67 04 18: OCTET STRING
+ : 61 64 6D 69 6E 40 6E 65 74 73 63 61 70 65 2E 63
+ : 6F 6D
+ 87 04 10: OCTET STRING
+ : 70 73 2D 63 61 70 69 74 6F 6C
+ 99 04 7: OCTET STRING
+ : 63 61 70 69 74 6F 6C
+ 108 02 1: INTEGER 80
+ 111 02 1: INTEGER 10
+ 114 02 1: INTEGER 1
+ : }
+ : }
+ : }
+ */
+ boolean critical = false;
+ int version = 1;
+ String streetAddress = "401E Middlefield Rd.,MV,CA94041";
+ String telephoneNumber = "650-111-1111";
+ String rfc822Name = "admin@netscape.com";
+ String ID = "ps-capitol";
+ String hostName = "capitol";
+ int portNumber = 80;
+ int maxUsers = 10;
+ int serviceLevel = 1;
+
+ PresenceServerExtension ext = new PresenceServerExtension(
+ critical,
+ version, streetAddress, telephoneNumber,
+ rfc822Name, ID, hostName, portNumber,
+ maxUsers, serviceLevel);
+
+ // encode
+
+ ByteArrayOutputStream dos = new ByteArrayOutputStream();
+ ext.encode(dos);
+ FileOutputStream fos = new FileOutputStream("pse.der");
+ fos.write(dos.toByteArray());
+ fos.close();
+
+ Extension ext1 = new Extension(new DerValue(dos.toByteArray()));
+
+ @SuppressWarnings("unused")
+ PresenceServerExtension ext2 = new PresenceServerExtension(
+ new Boolean(false), ext1.getExtensionValue());
+
+ }
+}
diff --git a/base/util/src/netscape/security/extensions/SubjectInfoAccessExtension.java b/base/util/src/netscape/security/extensions/SubjectInfoAccessExtension.java
new file mode 100644
index 000000000..5c373289f
--- /dev/null
+++ b/base/util/src/netscape/security/extensions/SubjectInfoAccessExtension.java
@@ -0,0 +1,254 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.extensions;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extension;
+import netscape.security.x509.GeneralName;
+import netscape.security.x509.URIName;
+
+/**
+ * This represents the subject information access extension
+ * as defined in RFC3280.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class SubjectInfoAccessExtension extends Extension implements CertAttrSet {
+ private static final long serialVersionUID = 7237321566602583325L;
+
+ public static final String NAME = "SubjectInfoAccessExtension";
+
+ public static final int OID_OCSP[] = { 1, 3, 6, 1, 5, 5, 7, 48, 1 };
+ public static final ObjectIdentifier METHOD_OCSP = new
+ ObjectIdentifier(OID_OCSP);
+
+ public static final int OID_CA_ISSUERS[] = { 1, 3, 6, 1, 5, 5, 7, 48, 2 };
+ public static final ObjectIdentifier METHOD_CA_ISSUERS = new
+ ObjectIdentifier(OID_CA_ISSUERS);
+
+ public static final int OID[] = { 1, 3, 6, 1, 5, 5, 7, 1, 11 };
+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID);
+
+ private Vector<AccessDescription> mDesc = new Vector<AccessDescription>();
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public SubjectInfoAccessExtension(boolean critical) {
+ this.extensionId = ID;
+ this.critical = critical;
+ this.extensionValue = null; // build this when encodeThis() is called
+ }
+
+ public SubjectInfoAccessExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = ID;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+ decodeThis();
+ }
+
+ /**
+ * Sets extension attribute.
+ */
+ public void set(String name, Object obj) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Retrieves extension attribute.
+ */
+ public Object get(String name) throws CertificateException {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Deletes attribute.
+ */
+ public void delete(String name) throws CertificateException {
+ // NOT USED
+ }
+
+ /**
+ * Decodes this extension.
+ */
+ public void decode(InputStream in) throws IOException {
+ // NOT USED
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ // NOT USED
+ return null;
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Adds Access Description.
+ */
+ public void addAccessDescription(
+ ObjectIdentifier method,
+ GeneralName gn) {
+ clearValue();
+ mDesc.addElement(new AccessDescription(method, gn));
+ }
+
+ public AccessDescription getAccessDescription(int pos) {
+ return mDesc.elementAt(pos);
+ }
+
+ /**
+ * Returns the number of access description.
+ */
+ public int numberOfAccessDescription() {
+ return mDesc.size();
+ }
+
+ private void decodeThis() throws IOException {
+ DerValue val = new DerValue(this.extensionValue);
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of AuthInfoAccess extension");
+ }
+ while (val.data.available() != 0) {
+ DerValue seq = val.data.getDerValue();
+ ObjectIdentifier method = seq.data.getDerValue().getOID();
+ GeneralName gn = new GeneralName(seq.data.getDerValue());
+
+ addAccessDescription(method, gn);
+ }
+ }
+
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < mDesc.size(); i++) {
+ DerOutputStream tmp0 = new DerOutputStream();
+ AccessDescription ad = mDesc.elementAt(i);
+
+ tmp0.putOID(ad.getMethod());
+ ad.getLocation().encode(tmp0);
+ tmp.write(DerValue.tag_Sequence, tmp0);
+ }
+ seq.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Returns a printable representation of the AuthInfoAccess.
+ */
+ public String toString() {
+ String s = super.toString() + "AuthInfoAccess [\n";
+
+ for (int i = 0; i < mDesc.size(); i++) {
+ AccessDescription ad = mDesc.elementAt(i);
+
+ s += "(" + i + ")";
+ s += " ";
+ s += ad.getMethod().toString() + " " + ad.getLocation().toString();
+ }
+ return (s + "]\n");
+ }
+
+ public static void main(String[] argv) {
+ AuthInfoAccessExtension aia = new AuthInfoAccessExtension(false);
+ GeneralName ocspName = new GeneralName(new
+ URIName("http://ocsp.netscape.com"));
+
+ aia.addAccessDescription(METHOD_OCSP, ocspName);
+ GeneralName caIssuersName = new GeneralName(new
+ URIName("http://ocsp.netscape.com"));
+
+ aia.addAccessDescription(METHOD_CA_ISSUERS, caIssuersName);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ try {
+ aia.encode(os);
+
+ System.out.println(Utils.base64encode(os.toByteArray()));
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ }
+
+ try {
+ // test serialization
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+ oos.writeObject(aia);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(
+ bos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bis);
+ AuthInfoAccessExtension clone = (AuthInfoAccessExtension)
+ ois.readObject();
+
+ System.out.println(clone);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/ContentInfo.java b/base/util/src/netscape/security/pkcs/ContentInfo.java
new file mode 100644
index 000000000..9825494c2
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/ContentInfo.java
@@ -0,0 +1,155 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * A ContentInfo type, as defined in PKCS#7.
+ *
+ * @version 1.12
+ * @author Benjamin Renaud
+ */
+
+public class ContentInfo {
+
+ // pkcs7 pre-defined content types
+ private static int[] pkcs7 = { 1, 2, 840, 113549, 1, 7 };
+ private static int[] data = { 1, 2, 840, 113549, 1, 7, 1 };
+ private static int[] sdata = { 1, 2, 840, 113549, 1, 7, 2 };
+ private static int[] edata = { 1, 2, 840, 113549, 1, 7, 3 };
+ private static int[] sedata = { 1, 2, 840, 113549, 1, 7, 4 };
+ private static int[] ddata = { 1, 2, 840, 113549, 1, 7, 5 };
+ private static int[] crdata = { 1, 2, 840, 113549, 1, 7, 6 };
+
+ public static final ObjectIdentifier PKCS7_OID =
+ new ObjectIdentifier(pkcs7);
+
+ public static final ObjectIdentifier DATA_OID =
+ new ObjectIdentifier(data);
+
+ public static final ObjectIdentifier SIGNED_DATA_OID =
+ new ObjectIdentifier(sdata);
+
+ public static final ObjectIdentifier ENVELOPED_DATA_OID =
+ new ObjectIdentifier(edata);
+
+ public static final ObjectIdentifier SIGNED_AND_ENVELOPED_DATA_OID =
+ new ObjectIdentifier(sedata);
+
+ public static final ObjectIdentifier DIGESTED_DATA_OID =
+ new ObjectIdentifier(ddata);
+
+ public static final ObjectIdentifier ENCRYPTED_DATA_OID =
+ new ObjectIdentifier(crdata);
+
+ ObjectIdentifier contentType;
+ DerValue content; // OPTIONAL
+
+ public ContentInfo(ObjectIdentifier contentType, DerValue content) {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ /**
+ * Make a contentInfo of type data.
+ */
+ public ContentInfo(byte[] bytes) {
+ DerValue octetString = new DerValue(DerValue.tag_OctetString, bytes);
+ this.contentType = DATA_OID;
+ this.content = octetString;
+ }
+
+ public ContentInfo(DerInputStream derin)
+ throws IOException, ParsingException {
+ DerInputStream disType;
+ DerInputStream disTaggedContent;
+ DerValue type;
+ DerValue taggedContent;
+ DerValue[] typeAndContent;
+ DerValue[] contents;
+
+ typeAndContent = derin.getSequence(2);
+
+ // Parse the content type
+ type = typeAndContent[0];
+ disType = new DerInputStream(type.toByteArray());
+ contentType = disType.getOID();
+
+ // Parse the content (OPTIONAL field).
+ // Skip the [0] EXPLICIT tag by pretending that the content is the one
+ // and only element in an implicitly tagged set
+ if (typeAndContent.length > 1) { // content is OPTIONAL
+ taggedContent = typeAndContent[1];
+ disTaggedContent = new DerInputStream(taggedContent.toByteArray());
+ contents = disTaggedContent.getSet(1, true);
+ content = contents[0];
+ }
+ }
+
+ public DerValue getContent() {
+ return content;
+ }
+
+ public byte[] getData() throws IOException {
+ if (contentType.equals(DATA_OID)) {
+ return content.getOctetString();
+ }
+ throw new IOException("content type is not DATA: " + contentType);
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream contentDerCode;
+ DerOutputStream seq;
+ DerValue taggedContent;
+
+ contentDerCode = new DerOutputStream();
+ content.encode(contentDerCode);
+ // Add the [0] EXPLICIT tag in front of the content encoding
+ taggedContent = new DerValue((byte) 0xA0,
+ contentDerCode.toByteArray());
+
+ seq = new DerOutputStream();
+ seq.putOID(contentType);
+ seq.putDerValue(taggedContent);
+
+ out.write(DerValue.tag_Sequence, seq);
+ }
+
+ /**
+ * Returns a byte array representation of the data held in
+ * the content field.
+ */
+ public byte[] getContentBytes() throws IOException {
+ DerInputStream dis = new DerInputStream(content.toByteArray());
+ return dis.getOctetString();
+ }
+
+ public String toString() {
+ String out = "";
+
+ out += "Content Info Sequence\n\tContent type: " + contentType + "\n";
+ out += "\tContent: " + content;
+ return out;
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/EncodingException.java b/base/util/src/netscape/security/pkcs/EncodingException.java
new file mode 100644
index 000000000..cb495e990
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/EncodingException.java
@@ -0,0 +1,33 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+public class EncodingException extends Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6126764125859196917L;
+
+ public EncodingException() {
+ super();
+ }
+
+ public EncodingException(String s) {
+ super(s);
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS10.java b/base/util/src/netscape/security/pkcs/PKCS10.java
new file mode 100644
index 000000000..a6ddd203f
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS10.java
@@ -0,0 +1,343 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X500Signer;
+import netscape.security.x509.X509Key;
+
+/**
+ * PKCS #10 certificate requests are created and sent to Certificate
+ * Authorities, which then create X.509 certificates and return them to
+ * the entity which created the certificate request. These cert requests
+ * basically consist of the subject's X.500 name and public key, signed
+ * using the corresponding private key.
+ *
+ * The ASN.1 syntax for a Certification Request is:
+ *
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm SignatureAlgorithmIdentifier,
+ * signature Signature
+ * }
+ *
+ * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
+ * Signature ::= BIT STRING
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version Version,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * attributes [0] IMPLICIT Attributes
+ * }
+ * Attributes ::= SET OF Attribute
+ * </pre>
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.28
+ */
+public class PKCS10 {
+ /**
+ * Constructs an unsigned PKCS #10 certificate request. Before this
+ * request may be used, it must be encoded and signed. Then it
+ * must be retrieved in some conventional format (e.g. string).
+ *
+ * @param publicKey the public key that should be placed
+ * into the certificate generated by the CA.
+ */
+ public PKCS10(X509Key publicKey) {
+ subjectPublicKeyInfo = publicKey;
+ attributeSet = new PKCS10Attributes();
+ }
+
+ /**
+ * Constructs an unsigned PKCS #10 certificate request. Before this
+ * request may be used, it must be encoded and signed. Then it
+ * must be retrieved in some conventional format (e.g. string).
+ *
+ * @param publicKey the public key that should be placed
+ * into the certificate generated by the CA.
+ * @param attributes additonal set of PKCS10 attributes requested
+ * for in the certificate.
+ */
+ public PKCS10(X509Key publicKey, PKCS10Attributes attributes) {
+ subjectPublicKeyInfo = publicKey;
+ if (attributes != null)
+ attributeSet = attributes;
+ else
+ attributeSet = new PKCS10Attributes();
+ }
+
+ /**
+ * Parses an encoded, signed PKCS #10 certificate request, verifying
+ * the request's signature as it does so. This constructor would
+ * typically be used by a Certificate Authority, from which a new
+ * certificate would then be constructed.
+ *
+ * @param data the DER-encoded PKCS #10 request.
+ * @param sigver boolean specifies signature verification enabled or not
+ * @exception IOException for low level errors reading the data
+ * @exception SignatureException when the signature is invalid
+ * @exception NoSuchAlgorithmException when the signature
+ * algorithm is not supported in this environment
+ */
+ public PKCS10(byte data[], boolean sigver)
+ throws IOException, SignatureException, NoSuchAlgorithmException, java.security.NoSuchProviderException {
+ DerInputStream in;
+ DerValue seq[];
+ AlgorithmId id;
+ byte sigData[];
+ Signature sig;
+
+ certificateRequest = data;
+
+ //
+ // Outer sequence: request, signature algorithm, signature.
+ // Parse, and prepare to verify later.
+ //
+ in = new DerInputStream(data);
+ seq = in.getSequence(3);
+
+ if (seq.length != 3)
+ throw new IllegalArgumentException("not a PKCS #10 request");
+
+ data = seq[0].toByteArray(); // reusing this variable
+ certRequestInfo = seq[0].toByteArray(); // make a copy
+ id = AlgorithmId.parse(seq[1]);
+ sigData = seq[2].getBitString();
+
+ //
+ // Inner sequence: version, name, key, attributes
+ //
+ @SuppressWarnings("unused")
+ BigInt serial = seq[0].data.getInteger(); // consume serial
+
+ /*
+ if (serial.toInt () != 0)
+ throw new IllegalArgumentException ("not PKCS #10 v1");
+ */
+
+ subject = new X500Name(seq[0].data);
+
+ byte val1[] = seq[0].data.getDerValue().toByteArray();
+ subjectPublicKeyInfo = X509Key.parse(new DerValue(val1));
+ PublicKey publicKey = X509Key.parsePublicKey(new DerValue(val1));
+
+ // Cope with a somewhat common illegal PKCS #10 format
+ if (seq[0].data.available() != 0)
+ attributeSet = new PKCS10Attributes(seq[0].data);
+ else
+ attributeSet = new PKCS10Attributes();
+
+ //
+ // OK, we parsed it all ... validate the signature using the
+ // key and signature algorithm we found.
+ // temporary commented out
+ try {
+ String idName = id.getName();
+ if (idName.equals("MD5withRSA"))
+ idName = "MD5/RSA";
+ else if (idName.equals("MD2withRSA"))
+ idName = "MD2/RSA";
+ else if (idName.equals("SHA1withRSA"))
+ idName = "SHA1/RSA";
+ else if (idName.equals("SHA1withDSA"))
+ idName = "SHA1/DSA";
+ else if (idName.equals("SHA1withEC"))
+ idName = "SHA1/EC";
+ else if (idName.equals("SHA256withEC"))
+ idName = "SHA256/EC";
+ else if (idName.equals("SHA384withEC"))
+ idName = "SHA384/EC";
+ else if (idName.equals("SHA512withEC"))
+ idName = "SHA512/EC";
+
+ if (sigver) {
+ sig = Signature.getInstance(idName, "Mozilla-JSS");
+
+ sig.initVerify(publicKey);
+ sig.update(data);
+ if (!sig.verify(sigData))
+ throw new SignatureException("Invalid PKCS #10 signature");
+ }
+ } catch (InvalidKeyException e) {
+ throw new SignatureException("invalid key");
+ }
+ }
+
+ public PKCS10(byte data[])
+ throws IOException, SignatureException, NoSuchAlgorithmException, java.security.NoSuchProviderException {
+ this(data, true);
+ }
+
+ /**
+ * Create the signed certificate request. This will later be
+ * retrieved in either string or binary format.
+ *
+ * @param requester identifies the signer (by X.500 name)
+ * and provides the private key used to sign.
+ * @exception IOException on errors.
+ * @exception CertificateException on certificate handling errors.
+ * @exception SignatureException on signature handling errors.
+ */
+ public void encodeAndSign(X500Signer requester)
+ throws CertificateException, IOException, SignatureException {
+ DerOutputStream out, scratch;
+ byte certificateRequestInfo[];
+ byte sig[];
+
+ if (certificateRequest != null)
+ throw new SignatureException("request is already signed");
+
+ subject = requester.getSigner();
+
+ /*
+ * Encode cert request info, wrap in a sequence for signing
+ */
+ scratch = new DerOutputStream();
+ scratch.putInteger(new BigInt(0)); // version zero
+ subject.encode(scratch); // X.500 name
+ subjectPublicKeyInfo.encode(scratch); // public key
+ attributeSet.encode(scratch);
+
+ out = new DerOutputStream();
+ out.write(DerValue.tag_Sequence, scratch); // wrap it!
+ certificateRequestInfo = out.toByteArray();
+ scratch = out;
+
+ /*
+ * Sign it ...
+ */
+ requester.update(certificateRequestInfo, 0,
+ certificateRequestInfo.length);
+ sig = requester.sign();
+
+ /*
+ * Build guts of SIGNED macro
+ */
+ requester.getAlgorithmId().encode(scratch); // sig algorithm
+ scratch.putBitString(sig); // sig
+
+ /*
+ * Wrap those guts in a sequence
+ */
+ out = new DerOutputStream();
+ out.write(DerValue.tag_Sequence, scratch);
+ certificateRequest = out.toByteArray();
+ }
+
+ /**
+ * Returns the subject's name.
+ */
+ public X500Name getSubjectName() {
+ return subject;
+ }
+
+ /**
+ * Returns the subject's public key.
+ */
+ public X509Key getSubjectPublicKeyInfo() {
+ return subjectPublicKeyInfo;
+ }
+
+ /**
+ * Returns the additional attributes requested.
+ */
+ public PKCS10Attributes getAttributes() {
+ return attributeSet;
+ }
+
+ /**
+ * Returns the encoded and signed certificate request as a
+ * DER-encoded byte array.
+ *
+ * @return the certificate request, or null if encodeAndSign()
+ * has not yet been called.
+ */
+ public byte[] toByteArray() {
+ return certificateRequest;
+ }
+
+ /**
+ * Prints an E-Mailable version of the certificate request on the print
+ * stream passed. The format is a common base64 encoded one, supported
+ * by most Certificate Authorities because Netscape web servers have
+ * used this for some time. Some certificate authorities expect some
+ * more information, in particular contact information for the web
+ * server administrator.
+ *
+ * @param out the print stream where the certificate request
+ * will be printed.
+ * @exception IOException when an output operation failed
+ * @exception SignatureException when the certificate request was
+ * not yet signed.
+ */
+ public void print(PrintStream out)
+ throws IOException, SignatureException {
+ if (certificateRequest == null)
+ throw new SignatureException("Cert request was not signed");
+
+ out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");
+ out.println(Utils.base64encode(certificateRequest));
+ out.println("-----END NEW CERTIFICATE REQUEST-----");
+ }
+
+ /**
+ * Provides a short description of this request.
+ */
+ public String toString() {
+ return "[PKCS #10 certificate request:\n"
+ + subjectPublicKeyInfo.toString()
+ + " subject: <" + subject + ">" + "\n"
+ + " attributes: " + attributeSet.toString()
+ + "\n]";
+ }
+
+ /**
+ * Retrieve the PKCS10 CertificateRequestInfo as a byte array
+ */
+ public byte[] getCertRequestInfo() {
+ return certRequestInfo;
+ }
+
+ private X500Name subject;
+ private X509Key subjectPublicKeyInfo;
+ private PKCS10Attributes attributeSet;
+
+ private byte certificateRequest[]; // signed
+ private byte certRequestInfo[]; // inner content signed
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS10Attribute.java b/base/util/src/netscape/security/pkcs/PKCS10Attribute.java
new file mode 100644
index 000000000..a649c395a
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS10Attribute.java
@@ -0,0 +1,238 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.CertificateException;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.ACertAttrSet;
+import netscape.security.x509.CertAttrSet;
+import netscape.security.x509.Extensions;
+import netscape.security.x509.OIDMap;
+
+/**
+ * Represent a PKCS Attribute.
+ *
+ * <p>
+ * Attributes are addiitonal attributes which can be inserted in a PKCS certificate request. For example a
+ * "Driving License Certificate" could have the driving license number as a attribute.
+ *
+ * <p>
+ * Attributes are represented as a sequence of the attribute identifier (Object Identifier) and a set of DER encoded
+ * attribute values. The current implementation only supports one value per attribute.
+ *
+ * ASN.1 definition of Attribute:
+ *
+ * <pre>
+ * Attribute :: SEQUENCE {
+ * type AttributeValue,
+ * values SET OF AttributeValue
+ * }
+ * AttributeValue ::= ANY
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.13
+ */
+public class PKCS10Attribute implements DerEncoder, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2002480042340316170L;
+ protected ObjectIdentifier attributeId = null;
+ protected CertAttrSet attributeValue = null;
+
+ /**
+ * Default constructor. Used only by sub-classes.
+ */
+ public PKCS10Attribute() {
+ }
+
+ /**
+ * Constructs an attribute from a DER encoded array of bytes.
+ */
+ public PKCS10Attribute(DerValue derVal) throws IOException {
+ if (derVal.tag != DerValue.tag_Sequence) {
+ throw new IOException("Sequence tag missing for PKCS10Attribute.");
+ }
+
+ DerInputStream in = derVal.toDerInputStream();
+ // Object identifier
+ attributeId = in.getOID();
+ // System.out.println("attribute ID in pkcs10 "+attributeId.toString());
+
+ // Rest of the stuff is attribute value(s), wrapped in a SET.
+ // For now, assume there is only one attribute value present.
+ DerValue[] inAttrValues = in.getSet(1);
+ int attrValueNum = inAttrValues.length;
+ if (attrValueNum > 1) {
+ throw new IOException("More than one value per attribute not supported");
+ }
+
+ // Read the first attribute value
+ DerValue inAttrValue = inAttrValues[0];
+
+ if (attributeId.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) {
+ //pkcs9 extensionAttr
+ try {
+ // remove the tag
+ //DerValue dv = inAttrValue.data.getDerValue();
+ // hack. toDerInputStream only gives one extension.
+ DerInputStream fi = new DerInputStream(inAttrValue.toByteArray());
+ attributeValue = (CertAttrSet) new
+ Extensions(fi);
+ //CertificateExtensions(fi);
+ return;
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+ byte[] val = inAttrValue.toByteArray();
+ Class<?>[] params = { Object.class };
+ try {
+ @SuppressWarnings("unchecked")
+ Class<CertAttrSet> extClass = (Class<CertAttrSet>) OIDMap.getClass(attributeId);
+ if (extClass != null) {
+ Constructor<CertAttrSet> cons = (Constructor<CertAttrSet>) extClass.getConstructor(params);
+ Object value = Array.newInstance(byte.class, val.length);
+ for (int i = 0; i < val.length; i++) {
+ Array.setByte(value, i, val[i]);
+ }
+ Object[] passed = new Object[] { value };
+ attributeValue = cons.newInstance(passed);
+ } else {
+ // attribute classes are usable for PKCS10 attributes.
+ // this is used where the attributes are not actual
+ // implemented extensions.
+ attributeValue = new ACertAttrSet(inAttrValue);
+ }
+ } catch (InvocationTargetException invk) {
+ throw new IOException(invk.getTargetException().getMessage());
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+
+ /**
+ * Constructs an attribute from individual components of ObjectIdentifier
+ * and the DER encoded value.
+ *
+ * @param attributeId the ObjectIdentifier of the attribute.
+ * @param attributeValue the CertAttrSet.
+ */
+ public PKCS10Attribute(ObjectIdentifier attributeId,
+ CertAttrSet attributeValue) {
+ this.attributeId = attributeId;
+ this.attributeValue = attributeValue;
+ }
+
+ /**
+ * Constructs an attribute from another attribute. To be used for
+ * creating decoded subclasses.
+ *
+ * @param attr the attribute to create from.
+ */
+ public PKCS10Attribute(PKCS10Attribute attr) {
+ this.attributeId = attr.attributeId;
+ this.attributeValue = attr.attributeValue;
+ }
+
+ /**
+ * Write the output to the DerOutputStream.
+ *
+ * @param out the OutputStream to write the attribute to.
+ * @exception CertificateException on certificate encoding errors.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ // Encode the attribute value
+ DerOutputStream outAttrValue = new DerOutputStream();
+ attributeValue.encode(outAttrValue);
+
+ // Wrap the encoded attribute value into a SET
+ DerValue outAttrValueSet = new DerValue(DerValue.tag_Set,
+ outAttrValue.toByteArray());
+
+ // Create the attribute
+ DerOutputStream outAttr = new DerOutputStream();
+ outAttr.putOID(attributeId);
+ outAttr.putDerValue(outAttrValueSet);
+
+ // Wrap the OID and the set of attribute values into a SEQUENCE
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.write(DerValue.tag_Sequence, outAttr);
+
+ // write the results to out
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the OutputStream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding errors.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ try {
+ encode(out);
+ } catch (CertificateException ce) {
+ IOException ioe = new IOException(ce.toString());
+ ioe.fillInStackTrace();
+ throw ioe;
+ }
+ }
+
+ /**
+ * Returns the ObjectIdentifier of the attribute.
+ */
+ public ObjectIdentifier getAttributeId() {
+ return (attributeId);
+ }
+
+ /**
+ * Returns the attribute value as an byte array for further processing.
+ */
+ public CertAttrSet getAttributeValue() {
+ return (attributeValue);
+ }
+
+ /**
+ * Returns the attribute in user readable form.
+ */
+ public String toString() {
+ String s = "AttributeId: " + attributeId.toString() + "\n";
+ s += "AttributeValue: " + attributeValue.toString();
+
+ return (s);
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS10Attributes.java b/base/util/src/netscape/security/pkcs/PKCS10Attributes.java
new file mode 100644
index 000000000..8beb1e64c
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS10Attributes.java
@@ -0,0 +1,147 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the PKCS10 attributes for the request.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.10
+ */
+public class PKCS10Attributes extends Vector<PKCS10Attribute> implements DerEncoder {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1362260612357629542L;
+ private Hashtable<String, PKCS10Attribute> map;
+
+ /**
+ * Default constructor for the certificate attribute.
+ */
+ public PKCS10Attributes() {
+ map = new Hashtable<String, PKCS10Attribute>();
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the attributes from.
+ * @exception IOException on decoding errors.
+ */
+ public PKCS10Attributes(DerInputStream in)
+ throws IOException {
+
+ map = new Hashtable<String, PKCS10Attribute>();
+ DerValue[] attrs = in.getSet(5, true);
+
+ if (attrs != null) {
+ for (int i = 0; i < attrs.length; i++) {
+ PKCS10Attribute attr = new PKCS10Attribute(attrs[i]);
+ addElement(attr);
+ map.put(attr.getAttributeValue().getName(), attr);
+ }
+ }
+ }
+
+ /**
+ * Encode the attributes in DER form to the stream.
+ *
+ * @param out the OutputStream to marshal the contents to.
+ *
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out)
+ throws IOException {
+ derEncode(out);
+ }
+
+ /**
+ * Encode the attributes in DER form to the stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out the OutputStream to marshal the contents to.
+ * @exception IOException on encoding errors.
+ */
+ public void derEncode(OutputStream out)
+ throws IOException {
+
+ // first copy the elements into an array
+ PKCS10Attribute[] attribs = new PKCS10Attribute[size()];
+ copyInto(attribs);
+
+ DerOutputStream attrOut = new DerOutputStream();
+ attrOut.putOrderedSetOf(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
+ attribs);
+
+ out.write(attrOut.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void setAttribute(String name, PKCS10Attribute attr) throws IOException {
+ map.put(name, attr);
+ addElement(attr);
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public PKCS10Attribute getAttribute(String name) throws IOException {
+ PKCS10Attribute attr = map.get(name);
+ /*
+ if (attr == null) {
+ throw new IOException("No attribute found with name " + name);
+ }
+ */
+ return (attr);
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void deleteAttribute(String name) throws IOException {
+ PKCS10Attribute attr = map.get(name);
+ if (attr == null) {
+ throw new IOException("No attribute found with name " + name);
+ }
+ map.remove(name);
+ removeElement(attr);
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<PKCS10Attribute> getElements() {
+ return map.elements();
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS7.java b/base/util/src/netscape/security/pkcs/PKCS7.java
new file mode 100644
index 000000000..c8fb69582
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS7.java
@@ -0,0 +1,446 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
+/**
+ * PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
+ * Supports only <tt>SignedData</tt> ContentInfo
+ * type, where to the type of data signed is plain Data.
+ * For signedData, <tt>crls</tt>, <tt>attributes</tt> and
+ * PKCS#6 Extended Certificates are not supported.
+ *
+ * @version 1.33 97/12/10
+ * @author Benjamin Renaud
+ */
+public class PKCS7 {
+
+ private ObjectIdentifier contentType;
+
+ // the ASN.1 members for a signedData (and other) contentTypes
+ private BigInt version;
+ private AlgorithmId[] digestAlgorithmIds;
+ private ContentInfo contentInfo;
+ private X509Certificate[] certificates;
+ private SignerInfo[] signerInfos;
+
+ /**
+ * Unmarshals a PKCS7 block from its encoded form, parsing the
+ * encoded bytes from the InputStream.
+ *
+ * @param in an input stream holding at least one PKCS7 block.
+ * @exception ParsingException on parsing errors.
+ * @exception IOException on other errors.
+ */
+ public PKCS7(InputStream in) throws ParsingException, IOException {
+ DataInputStream dis = new DataInputStream(in);
+
+ int len = 0;
+ byte[] newbuf = new byte[len];
+ byte[] oldbuf = new byte[len];
+ byte[] data = new byte[len];
+
+ do {
+ newbuf = new byte[dis.available()];
+ len += dis.available();
+ dis.readFully(newbuf);
+ data = new byte[len];
+
+ System.arraycopy(oldbuf, 0, data, 0, oldbuf.length);
+ System.arraycopy(newbuf, 0, data, oldbuf.length, newbuf.length);
+ oldbuf = new byte[len];
+ System.arraycopy(data, 0, oldbuf, 0, data.length);
+
+ } while (dis.available() > 0);
+
+ parse(new DerInputStream(data));
+ }
+
+ /**
+ * Unmarshals a PKCS7 block from its encoded form, parsing the
+ * encoded bytes from the DerInputStream.
+ *
+ * @param derin a DerInputStream holding at least one PKCS7 block.
+ * @exception ParsingException on parsing errors.
+ */
+ public PKCS7(DerInputStream derin) throws ParsingException {
+ parse(derin);
+ }
+
+ /**
+ * Unmarshals a PKCS7 block from its encoded form, parsing the
+ * encoded bytes.
+ *
+ * @param bytes the encoded bytes.
+ * @exception ParsingException on parsing errors.
+ */
+ public PKCS7(byte[] bytes) throws ParsingException {
+ DerInputStream derin = new DerInputStream(bytes);
+ parse(derin);
+ }
+
+ private void parse(DerInputStream derin) throws ParsingException {
+ try {
+ ContentInfo contentInfo = new ContentInfo(derin);
+ contentType = contentInfo.contentType;
+ if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) {
+ parseSignedData(contentInfo.getContent());
+ } else {
+ throw new ParsingException("content type " + contentType +
+ " not supported.");
+ }
+ } catch (IOException e) {
+ ParsingException pe =
+ new ParsingException("IOException: " + e.getMessage());
+ pe.fillInStackTrace();
+ throw pe;
+ }
+ }
+
+ /**
+ * Construct an initialized PKCS7 block.
+ *
+ * @param digestAlgorithmIds the message digest algorithm identifiers.
+ * @param contentInfo the content information.
+ * @param certificates an array of X.509 certificates.
+ * @param signerInfos an array of signer information.
+ */
+ public PKCS7(AlgorithmId[] digestAlgorithmIds,
+ ContentInfo contentInfo,
+ X509Certificate[] certificates,
+ SignerInfo[] signerInfos) {
+
+ version = new BigInt(1);
+ this.digestAlgorithmIds = digestAlgorithmIds;
+ this.contentInfo = contentInfo;
+ this.certificates = certificates;
+ this.signerInfos = signerInfos;
+ }
+
+ private void parseSignedData(DerValue val)
+ throws ParsingException, IOException {
+
+ DerInputStream dis = val.toDerInputStream();
+
+ // Version
+ version = dis.getInteger();
+
+ // digestAlgorithmIds
+ DerValue[] digestAlgorithmIdVals = dis.getSet(1);
+ int len = digestAlgorithmIdVals.length;
+ digestAlgorithmIds = new AlgorithmId[len];
+ try {
+ for (int i = 0; i < len; i++) {
+ DerValue oid = digestAlgorithmIdVals[i];
+ digestAlgorithmIds[i] = AlgorithmId.parse(oid);
+ }
+
+ } catch (IOException e) {
+ ParsingException pe =
+ new ParsingException("Error parsing digest AlgorithmId IDs: " +
+ e.getMessage());
+ pe.fillInStackTrace();
+ throw pe;
+ }
+ // contentInfo
+ contentInfo = new ContentInfo(dis);
+
+ /*
+ * check if certificates (implicit tag) are provided
+ * (certificates are OPTIONAL)
+ */
+ if ((byte) (dis.peekByte()) == (byte) 0xA0) {
+ DerValue[] certificateVals = dis.getSet(2, true);
+
+ len = certificateVals.length;
+ certificates = new X509Certificate[len];
+
+ for (int i = 0; i < len; i++) {
+ try {
+ X509Certificate cert = (X509Certificate) new
+ X509CertImpl(certificateVals[i]);
+ certificates[i] = cert;
+ } catch (CertificateException e) {
+ ParsingException pe =
+ new ParsingException("CertificateException: " +
+ e.getMessage());
+ pe.fillInStackTrace();
+ throw pe;
+ }
+ }
+ }
+
+ // check if crls (implicit tag) are provided (crls are OPTIONAL)
+ if ((byte) (dis.peekByte()) == (byte) 0xA1) {
+ dis.getSet(0, true);
+ }
+
+ // signerInfos
+ DerValue[] signerInfoVals = dis.getSet(1);
+
+ len = signerInfoVals.length;
+ signerInfos = new SignerInfo[len];
+
+ for (int i = 0; i < len; i++) {
+ DerInputStream in = signerInfoVals[i].toDerInputStream();
+ signerInfos[i] = new SignerInfo(in);
+ }
+
+ }
+
+ /**
+ * Encodes the signed data to an output stream.
+ *
+ * @param out the output stream to write the encoded data to.
+ * @exception IOException on encoding errors.
+ */
+ public void encodeSignedData(OutputStream out) throws IOException {
+ DerOutputStream derout = new DerOutputStream();
+ encodeSignedData(derout, true);
+ out.write(derout.toByteArray());
+ }
+
+ /**
+ * Like method above but not sorted.
+ */
+ public void encodeSignedData(OutputStream out, boolean sort)
+ throws IOException {
+ DerOutputStream derout = new DerOutputStream();
+ encodeSignedData(derout, sort);
+ out.write(derout.toByteArray());
+ }
+
+ /**
+ * encode signed data, sort certs by default.
+ */
+ public void encodeSignedData(DerOutputStream out)
+ throws IOException {
+ encodeSignedData(out, true);
+ }
+
+ /**
+ * Encodes the signed data to a DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the encoded data to.
+ * @exception IOException on encoding errors.
+ */
+ public void encodeSignedData(DerOutputStream out, boolean sort)
+ throws IOException {
+
+ DerOutputStream signedData = new DerOutputStream();
+
+ // version
+ signedData.putInteger(version);
+
+ // digestAlgorithmIds
+ signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
+
+ // contentInfo
+ contentInfo.encode(signedData);
+
+ // cast to X509CertImpl[] since X509CertImpl implements DerEncoder
+ X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
+ try {
+ for (int i = 0; i < certificates.length; i++) {
+ implCerts[i] = (X509CertImpl) certificates[i];
+ }
+ } catch (ClassCastException e) {
+ IOException ioe =
+ new IOException("Certificates in PKCS7 " +
+ "must be of class " +
+ "netscape.security.X509CertImpl");
+ ioe.fillInStackTrace();
+ }
+
+ // Add the certificate set (tagged with [0] IMPLICIT)
+ // to the signed data
+ if (sort) {
+ signedData.putOrderedSetOf((byte) 0xA0, implCerts);
+ } else {
+ signedData.putSet((byte) 0xA0, implCerts);
+ }
+
+ // no crls (OPTIONAL field)
+
+ // signerInfos
+ signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
+
+ // making it a signed data block
+ DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence,
+ signedData.toByteArray());
+
+ // making it a content info sequence
+ ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID,
+ signedDataSeq);
+
+ // writing out the contentInfo sequence
+ block.encode(out);
+ }
+
+ /**
+ * This verifies a given SignerInfo.
+ *
+ * @param info the signer information.
+ * @param bytes the DER encoded content information.
+ *
+ * @exception NoSuchAlgorithmException on unrecognized algorithms.
+ * @exception SignatureException on signature handling errors.
+ */
+ public SignerInfo verify(SignerInfo info, byte[] bytes)
+ throws NoSuchAlgorithmException, SignatureException {
+ return info.verify(this, bytes);
+ }
+
+ /**
+ * Returns all signerInfos which self-verify.
+ *
+ * @param bytes the DER encoded content information.
+ *
+ * @exception NoSuchAlgorithmException on unrecognized algorithms.
+ * @exception SignatureException on signature handling errors.
+ */
+ public SignerInfo[] verify(byte[] bytes)
+ throws NoSuchAlgorithmException, SignatureException {
+
+ Vector<SignerInfo> intResult = new Vector<SignerInfo>();
+ for (int i = 0; i < signerInfos.length; i++) {
+
+ SignerInfo signerInfo = verify(signerInfos[i], bytes);
+ if (signerInfo != null) {
+ intResult.addElement(signerInfo);
+ }
+ }
+ if (intResult.size() != 0) {
+
+ SignerInfo[] result = new SignerInfo[intResult.size()];
+ intResult.copyInto(result);
+ return result;
+ }
+ return null;
+ }
+
+ /**
+ * Returns all signerInfos which self-verify.
+ *
+ * @exception NoSuchAlgorithmException on unrecognized algorithms.
+ * @exception SignatureException on signature handling errors.
+ */
+ public SignerInfo[] verify()
+ throws NoSuchAlgorithmException, SignatureException {
+ return verify(null);
+ }
+
+ /**
+ * Returns the version number of this PKCS7 block.
+ */
+ public BigInt getVersion() {
+ return version;
+ }
+
+ /**
+ * Returns the message digest algorithms specified in this PKCS7 block.
+ */
+ public AlgorithmId[] getDigestAlgorithmIds() {
+ return digestAlgorithmIds;
+ }
+
+ /**
+ * Returns the content information specified in this PKCS7 block.
+ */
+ public ContentInfo getContentInfo() {
+ return contentInfo;
+ }
+
+ /**
+ * Returns the X.509 certificates listed in this PKCS7 block.
+ */
+ public X509Certificate[] getCertificates() {
+ return certificates;
+ }
+
+ /**
+ * Returns the signer's information specified in this PKCS7 block.
+ */
+ public SignerInfo[] getSignerInfos() {
+ return signerInfos;
+ }
+
+ /**
+ * Returns the X.509 certificate listed in this PKCS7 block
+ * which has a matching serial number and Issuer name, or
+ * null if one is not found.
+ *
+ * @param serial the serial number of the certificate to retrieve.
+ * @param name the Distinguished Name of the Issuer.
+ */
+ public X509Certificate getCertificate(BigInt serial, X500Name name) {
+
+ for (int i = 0; i < certificates.length; i++) {
+ X509Certificate cert = certificates[i];
+ X500Name thisName = (X500Name) cert.getIssuerDN();
+ BigInteger tmpSerial = (BigInteger) cert.getSerialNumber();
+ BigInt thisSerial = new BigInt(tmpSerial);
+ if (serial.equals(thisSerial) && name.equals(thisName)) {
+ return cert;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the PKCS7 block in a printable string form.
+ */
+ public String toString() {
+ String out = "";
+
+ out += "PKCS7 :: version: " + version + "\n";
+ out += "PKCS7 :: digest AlgorithmIds: \n";
+ for (int i = 0; i < digestAlgorithmIds.length; i++) {
+ out += "\t" + digestAlgorithmIds[i] + "\n";
+ }
+ out += contentInfo + "\n";
+ out += "PKCS7 :: certificates: \n";
+ for (int i = 0; i < certificates.length; i++) {
+ out += "\t" + i + ". " + certificates[i] + "\n";
+ }
+ out += "PKCS7 :: signer infos: \n";
+ for (int i = 0; i < signerInfos.length; i++) {
+ out += ("\t" + i + ". " + signerInfos[i] + "\n");
+ }
+ return out;
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS8Key.java b/base/util/src/netscape/security/pkcs/PKCS8Key.java
new file mode 100644
index 000000000..7c5f64582
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS8Key.java
@@ -0,0 +1,435 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.AlgorithmId;
+
+/**
+ * Holds a PKCS#8 key, for example a private key
+ *
+ * @version 1.30, 97/12/10
+ * @author Dave Brownell
+ * @author Benjamin Renaud
+ */
+public class PKCS8Key implements PrivateKey {
+
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = -3836890099307167124L;
+
+ /* The algorithm information (name, parameters, etc). */
+ protected AlgorithmId algid;
+
+ /* The key bytes, without the algorithm information */
+ protected byte[] key;
+
+ /* The encoded for the key. */
+ protected byte[] encodedKey;
+
+ /* The version for this key */
+ public static final BigInteger VERSION = BigInteger.valueOf(0);
+
+ /**
+ * Default constructor. The key constructed must have its key
+ * and algorithm initialized before it may be used, for example
+ * by using <code>decode</code>.
+ */
+ public PKCS8Key() {
+ }
+
+ /**
+ * Construct PKCS#8 subject public key from a DER value. If
+ * the runtime environment is configured with a specific class for
+ * this kind of key, a subclass is returned. Otherwise, a generic
+ * PKCS8Key object is returned.
+ *
+ * <P>
+ * This mechanism gurantees that keys (and algorithms) may be freely manipulated and transferred, without risk of
+ * losing information. Also, when a key (or algorithm) needs some special handling, that specific need can be
+ * accomodated.
+ *
+ * @param in the DER-encoded SubjectPublicKeyInfo value
+ * @exception IOException on data format errors
+ */
+ public static PKCS8Key parse(DerValue in) throws IOException {
+ AlgorithmId algorithm;
+ PKCS8Key subjectKey;
+
+ if (in.tag != DerValue.tag_Sequence)
+ throw new IOException("corrupt private key");
+
+ BigInteger parsedVersion = in.data.getInteger().toBigInteger();
+ if (!VERSION.equals(parsedVersion)) {
+ throw new IOException("version mismatch: (supported: " +
+ VERSION + ", parsed: " +
+ parsedVersion);
+ }
+
+ algorithm = AlgorithmId.parse(in.data.getDerValue());
+
+ try {
+ subjectKey = buildPKCS8Key(algorithm, in.data.getOctetString());
+
+ } catch (InvalidKeyException e) {
+ throw new IOException("corrupt private key");
+ }
+
+ if (in.data.available() != 0)
+ throw new IOException("excess private key");
+ return subjectKey;
+ }
+
+ /**
+ * Parse the key bits. This may be redefined by subclasses to take
+ * advantage of structure within the key. For example, RSA public
+ * keys encapsulate two unsigned integers (modulus and exponent) as
+ * DER values within the <code>key</code> bits; Diffie-Hellman and
+ * DSS/DSA keys encapsulate a single unsigned integer.
+ *
+ * <P>
+ * This function is called when creating PKCS#8 SubjectPublicKeyInfo values using the PKCS8Key member functions,
+ * such as <code>parse</code> and <code>decode</code>.
+ *
+ * @exception IOException if a parsing error occurs.
+ * @exception InvalidKeyException if the key encoding is invalid.
+ */
+ protected void parseKeyBits() throws IOException, InvalidKeyException {
+ encode();
+ }
+
+ /*
+ * Factory interface, building the kind of key associated with this
+ * specific algorithm ID or else returning this generic base class.
+ * See the description above.
+ */
+ public static PKCS8Key buildPKCS8Key(AlgorithmId algid, byte[] key)
+ throws IOException, InvalidKeyException {
+ /*
+ * Use the algid and key parameters to produce the ASN.1 encoding
+ * of the key, which will then be used as the input to the
+ * key factory.
+ */
+ DerOutputStream pkcs8EncodedKeyStream = new DerOutputStream();
+ encode(pkcs8EncodedKeyStream, algid, key);
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pkcs8EncodedKeyStream.toByteArray());
+
+ try {
+ // Instantiate the key factory of the appropriate algorithm
+ KeyFactory keyFac = KeyFactory.getInstance(algid.getName());
+
+ // Generate the private key
+ PrivateKey privKey = keyFac.generatePrivate(pkcs8KeySpec);
+
+ if (privKey instanceof PKCS8Key) {
+ /*
+ * Return specialized PKCS8Key, where the structure within the
+ * key has been parsed
+ */
+ return (PKCS8Key) privKey;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ // Return generic PKCS8Key with opaque key data (see below)
+ } catch (InvalidKeySpecException e) {
+ // Return generic PKCS8Key with opaque key data (see below)
+ }
+
+ /*
+ * Try again using JDK1.1-style for backwards compatibility.
+ */
+ String classname = "";
+ try {
+ Provider sunProvider;
+
+ sunProvider = Security.getProvider("SUN");
+ if (sunProvider == null)
+ throw new InstantiationException();
+ classname = sunProvider.getProperty("PrivateKey.PKCS#8." +
+ algid.getName());
+ if (classname == null) {
+ throw new InstantiationException();
+ }
+
+ Class<?> keyClass = Class.forName(classname);
+ Object inst;
+ PKCS8Key result;
+
+ inst = keyClass.newInstance();
+ if (inst instanceof PKCS8Key) {
+ result = (PKCS8Key) inst;
+ result.algid = algid;
+ result.key = key;
+ result.parseKeyBits();
+ return result;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (InstantiationException e) {
+ } catch (IllegalAccessException e) {
+ // this should not happen.
+ throw new IOException(classname + " [internal error]");
+ }
+
+ PKCS8Key result = new PKCS8Key();
+ result.algid = algid;
+ result.key = key;
+ return result;
+ }
+
+ /**
+ * Returns the algorithm to be used with this key.
+ */
+ public String getAlgorithm() {
+ return algid.getName();
+ }
+
+ /**
+ * Returns the algorithm ID to be used with this key.
+ */
+ public AlgorithmId getAlgorithmId() {
+ return algid;
+ }
+
+ /**
+ * PKCS#8 sequence on the DER output stream.
+ */
+ public final void encode(DerOutputStream out) throws IOException {
+ encode(out, this.algid, this.key);
+ }
+
+ /**
+ * Returns the DER-encoded form of the key as a byte array.
+ */
+ public synchronized byte[] getEncoded() {
+ byte[] result = null;
+ try {
+ result = encode();
+ } catch (InvalidKeyException e) {
+ }
+ return result;
+ }
+
+ /**
+ * Returns the format for this key: "PKCS#8"
+ */
+ public String getFormat() {
+ return "PKCS#8";
+ }
+
+ /**
+ * Returns the DER-encoded form of the key as a byte array.
+ *
+ * @exception InvalidKeyException if an encoding error occurs.
+ */
+ public byte[] encode() throws InvalidKeyException {
+ if (encodedKey == null) {
+ try {
+ DerOutputStream out;
+
+ out = new DerOutputStream();
+ encode(out);
+ encodedKey = out.toByteArray();
+
+ } catch (IOException e) {
+ throw new InvalidKeyException("IOException : " +
+ e.getMessage());
+ }
+ }
+ return copyEncodedKey(encodedKey);
+ }
+
+ /*
+ * Returns a printable representation of the key
+ */
+ public String toString() {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String keybits = pp.toHexString(key);
+
+ return "algorithm = " + algid.toString()
+ + ", unparsed keybits = \n" + keybits;
+ }
+
+ /**
+ * Initialize an PKCS8Key object from an input stream. The data
+ * on that input stream must be encoded using DER, obeying the
+ * PKCS#8 format: a sequence consisting of a version, an algorithm
+ * ID and a bit string which holds the key. (That bit string is
+ * often used to encapsulate another DER encoded sequence.)
+ *
+ * <P>
+ * Subclasses should not normally redefine this method; they should instead provide a <code>parseKeyBits</code>
+ * method to parse any fields inside the <code>key</code> member.
+ *
+ * @param in an input stream with a DER-encoded PKCS#8
+ * SubjectPublicKeyInfo value
+ *
+ * @exception InvalidKeyException if a parsing error occurs.
+ */
+ public void decode(InputStream in) throws InvalidKeyException {
+ DerValue val;
+
+ try {
+ val = new DerValue(in);
+ if (val.tag != DerValue.tag_Sequence)
+ throw new InvalidKeyException("invalid key format");
+
+ BigInteger version = val.data.getInteger().toBigInteger();
+ if (!version.equals(PKCS8Key.VERSION)) {
+ throw new IOException("version mismatch: (supported: " +
+ PKCS8Key.VERSION + ", parsed: " +
+ version);
+ }
+ algid = AlgorithmId.parse(val.data.getDerValue());
+ key = val.data.getOctetString();
+ parseKeyBits();
+ if (val.data.available() != 0)
+ throw new InvalidKeyException("excess key data");
+
+ } catch (IOException e) {
+ // e.printStackTrace ();
+ throw new InvalidKeyException("IOException : " +
+ e.getMessage());
+ }
+ }
+
+ public void decode(byte[] encodedKey) throws InvalidKeyException {
+ decode(new ByteArrayInputStream(encodedKey));
+ }
+
+ /**
+ * Serialization write ... PKCS#8 keys serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void
+ writeObject(java.io.ObjectOutputStream stream)
+ throws IOException {
+ stream.write(getEncoded());
+ }
+
+ /**
+ * Serialization read ... PKCS#8 keys serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void readObject(ObjectInputStream stream)
+ throws IOException {
+
+ try {
+ decode(stream);
+
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ throw new IOException("deserialized key is invalid: " +
+ e.getMessage());
+ }
+ }
+
+ /*
+ * Make a copy of the encoded key.
+ */
+ private byte[] copyEncodedKey(byte[] encodedKey) {
+ int len = encodedKey.length;
+ byte[] copy = new byte[len];
+ System.arraycopy(encodedKey, 0, copy, 0, len);
+ return copy;
+ }
+
+ /*
+ * Produce PKCS#8 encoding from algorithm id and key material.
+ */
+ static void encode(DerOutputStream out, AlgorithmId algid, byte[] key)
+ throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(VERSION.toByteArray()));
+ algid.encode(tmp);
+ tmp.putOctetString(key);
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /**
+ * Compares two private keys. This returns false if the object with which
+ * to compare is not of type <code>Key</code>.
+ * Otherwise, the encoding of this key object is compared with the
+ * encoding of the given key object.
+ *
+ * @param object the object with which to compare
+ * @return <code>true</code> if this key has the same encoding as the
+ * object argument; <code>false</code> otherwise.
+ */
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object instanceof Key) {
+
+ // this encoding
+ byte[] b1;
+ if (encodedKey != null) {
+ b1 = encodedKey;
+ } else {
+ b1 = getEncoded();
+ }
+
+ // that encoding
+ byte[] b2 = ((Key) object).getEncoded();
+
+ // do the comparison
+ int i;
+ if (b1.length != b2.length)
+ return false;
+ for (i = 0; i < b1.length; i++) {
+ if (b1[i] != b2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculates a hash code value for this object. Objects
+ * which are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+ byte[] b1 = getEncoded();
+
+ for (int i = 1; i < b1.length; i++) {
+ retval += b1[i] * i;
+ }
+ return (retval);
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS9Attribute.java b/base/util/src/netscape/security/pkcs/PKCS9Attribute.java
new file mode 100644
index 000000000..6a6fd7dc9
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS9Attribute.java
@@ -0,0 +1,1123 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Date;
+import java.util.Hashtable;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.CertificateExtensions;
+
+/**
+ * Class supporting any PKCS9 attribute except
+ * ExtendedCertificateAttribute. Supports DER decoding and access to
+ * attribute values, but not DER encoding or setting of values.
+ *
+ * @version 1.2 97/12/10
+ * @author Douglas Hoover
+ */
+public class PKCS9Attribute implements DerEncoder {
+
+ /*
+ * OIDs of PKCS #9 attribute types.
+ */
+ private static final String RSADSI_str = "1.2.840.113549";
+ private static final String PKCS_str = RSADSI_str + ".1";
+ private static final String PKCS9_str = PKCS_str + ".9";
+
+ /**
+ * Array of attribute OIDs defined in PKCS9, by number.
+ */
+ static final ObjectIdentifier[] PKCS9_OIDS =
+ //new ObjectIdentifier[10];
+ // There are some Obsolete(?) attribute identifiers.
+ // This is mainly for extensionRequest (14) in pkcs10.
+ // We just add the other 4 as by products.
+ new ObjectIdentifier[15];
+
+ static { // static initializer for PKCS9_OIDS
+ for (int i = 1; i < PKCS9_OIDS.length; i++) {
+ PKCS9_OIDS[i] = new ObjectIdentifier(PKCS9_str + "." + i);
+ }
+ }
+
+ public static final ObjectIdentifier EMAIL_ADDRESS_OID = PKCS9_OIDS[1];
+ public static final ObjectIdentifier UNSTRUCTURED_NAME_OID = PKCS9_OIDS[2];
+ public static final ObjectIdentifier CONTENT_TYPE_OID = PKCS9_OIDS[3];
+ public static final ObjectIdentifier MESSAGE_DIGEST_OID = PKCS9_OIDS[4];
+ public static final ObjectIdentifier SIGNING_TIME_OID = PKCS9_OIDS[5];
+ public static final ObjectIdentifier COUNTERSIGNATURE_OID = PKCS9_OIDS[6];
+ public static final ObjectIdentifier CHALLENGE_PASSWORD_OID = PKCS9_OIDS[7];
+ public static final ObjectIdentifier UNSTRUCTURED_ADDRESS_OID = PKCS9_OIDS[8];
+ public static final ObjectIdentifier EXTENDED_CERTIFICATE_ATTRIBUTES_OID = PKCS9_OIDS[9];
+
+ public static final ObjectIdentifier ISSUER_AND_SERIALNUMBER_OID = PKCS9_OIDS[10];
+ public static final ObjectIdentifier PASSWORD_CHECK_OID = PKCS9_OIDS[11];
+ public static final ObjectIdentifier PUBLIC_KEY_OID = PKCS9_OIDS[12];
+ public static final ObjectIdentifier SIGNING_DESCRIPTION_OID = PKCS9_OIDS[13];
+ public static final ObjectIdentifier EXTENSION_REQUEST_OID = PKCS9_OIDS[14];
+
+ public static final String EMAIL_ADDRESS_STR = "EmailAddress";
+ public static final String UNSTRUCTURED_NAME_STR = "UnstructuredName";
+ public static final String CONTENT_TYPE_STR = "ContentType";
+ public static final String MESSAGE_DIGEST_STR = "MessageDigest";
+ public static final String SIGNING_TIME_STR = "SigningTime";
+ public static final String COUNTERSIGNATURE_STR = "Countersignature";
+ public static final String CHALLENGE_PASSWORD_STR = "ChallengePassword";
+ public static final String UNSTRUCTURED_ADDRESS_STR = "UnstructuredAddress";
+ public static final String EXTENDED_CERTIFICATE_ATTRIBUTES_STR = "ExtendedCertificateAttributes";
+
+ public static final String ISSUER_AND_SERIALNUMBER_STR = "IssuerAndSerialNumber";
+ public static final String PASSWORD_CHECK_STR = "PasswordCheck";
+ public static final String PUBLIC_KEY_STR = "PublicKey";
+ public static final String SIGNING_DESCRIPTION_STR = "SigningDescription";
+ public static final String EXTENSION_REQUEST_STR = "ExtensionRequest";
+
+ /**
+ * Hashtable mapping names and variant names of supported
+ * attributes to their OIDs. This table contains all name forms
+ * that occur in PKCS9, in lower case.
+ */
+ private static final Hashtable<String, ObjectIdentifier> NAME_OID_TABLE = new Hashtable<String, ObjectIdentifier>(
+ 28);
+
+ static { // static initializer for PCKS9_NAMES
+ NAME_OID_TABLE.put("emailaddress", PKCS9_OIDS[1]);
+ NAME_OID_TABLE.put("unstructuredname", PKCS9_OIDS[2]);
+ NAME_OID_TABLE.put("contenttype", PKCS9_OIDS[3]);
+ NAME_OID_TABLE.put("messagedigest", PKCS9_OIDS[4]);
+ NAME_OID_TABLE.put("signingtime", PKCS9_OIDS[5]);
+ NAME_OID_TABLE.put("countersignature", PKCS9_OIDS[6]);
+ NAME_OID_TABLE.put("challengepassword", PKCS9_OIDS[7]);
+ NAME_OID_TABLE.put("unstructuredaddress", PKCS9_OIDS[8]);
+ NAME_OID_TABLE.put("extendedcertificateattributes", PKCS9_OIDS[9]);
+
+ NAME_OID_TABLE.put("issuerandserialNumber", PKCS9_OIDS[10]);
+ NAME_OID_TABLE.put("passwordcheck", PKCS9_OIDS[11]);
+ NAME_OID_TABLE.put("publickey", PKCS9_OIDS[12]);
+ NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]);
+ NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]);
+ };
+
+ /**
+ * Hashtable mapping attribute OIDs defined in PKCS9 to the
+ * corresponding attribute value type.
+ */
+ private static final Hashtable<ObjectIdentifier, String> OID_NAME_TABLE = new Hashtable<ObjectIdentifier, String>(
+ 14);
+ static {
+ OID_NAME_TABLE.put(PKCS9_OIDS[1], EMAIL_ADDRESS_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[2], UNSTRUCTURED_NAME_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[3], CONTENT_TYPE_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[4], MESSAGE_DIGEST_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[5], SIGNING_TIME_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[6], COUNTERSIGNATURE_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[7], CHALLENGE_PASSWORD_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[8], UNSTRUCTURED_ADDRESS_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[9], EXTENDED_CERTIFICATE_ATTRIBUTES_STR);
+
+ OID_NAME_TABLE.put(PKCS9_OIDS[10], ISSUER_AND_SERIALNUMBER_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[11], PASSWORD_CHECK_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[12], PUBLIC_KEY_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[13], SIGNING_DESCRIPTION_STR);
+ OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR);
+ }
+
+ /**
+ * Acceptable ASN.1 tags for DER encodings of values of PKCS9
+ * attributes, by index in <code>PKCS9_OIDS</code>.
+ * Sets of acceptable tags are represented as arrays.
+ */
+ private static final Byte[][] PKCS9_VALUE_TAGS = {
+ null,
+ { Byte.valueOf(DerValue.tag_IA5String) }, // EMailAddress
+ { Byte.valueOf(DerValue.tag_IA5String) }, // UnstructuredName
+ { Byte.valueOf(DerValue.tag_ObjectId) }, // ContentType
+ { Byte.valueOf(DerValue.tag_OctetString) }, // MessageDigest
+ { Byte.valueOf(DerValue.tag_UtcTime) }, // SigningTime
+ { Byte.valueOf(DerValue.tag_Sequence) }, // Countersignature
+ { Byte.valueOf(DerValue.tag_PrintableString),
+ Byte.valueOf(DerValue.tag_T61String) }, // ChallengePassword
+ { Byte.valueOf(DerValue.tag_PrintableString),
+ Byte.valueOf(DerValue.tag_T61String) }, // UnstructuredAddress
+ { Byte.valueOf(DerValue.tag_SetOf) }, // ExtendedCertificateAttributes
+
+ null, //IssuerAndSerialNumber
+ null, //PasswordCheck
+ null, //PublicKey
+ null, //SigningDescription
+ { Byte.valueOf(DerValue.tag_Sequence) } //ExtensionRequest
+ };
+
+ /**
+ * Class types required for values for a given PKCS9
+ * attribute type.
+ *
+ * <P>
+ * The following table shows the correspondence between attribute types and value component classes.
+ *
+ * <P>
+ * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
+ *
+ * <TR>
+ * <TH>OID</TH>
+ * <TH>Attribute Type Name</TH>
+ * <TH>Kind</TH>
+ * <TH>Value Class</TH>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.1</TD>
+ * <TD>EmailAddress</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.2</TD>
+ * <TD>UnstructuredName</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.3</TD>
+ * <TD>ContentType</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>ObjectIdentifier</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.4</TD>
+ * <TD>MessageDigest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>byte[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.5</TD>
+ * <TD>SigningTime</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Date</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.6</TD>
+ * <TD>Countersignature</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>SignerInfo</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.7</TD>
+ * <TD>ChallengePassword</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.8</TD>
+ * <TD>UnstructuredAddress</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.9</TD>
+ * <TD>ExtendedCertificateAttributes</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.10</TD>
+ * <TD>IssuerAndSerialNumber</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.11</TD>
+ * <TD>PasswordCheck</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.12</TD>
+ * <TD>PublicKey</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.13</TD>
+ * <TD>SigningDescription</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.14</TD>
+ * <TD>ExtensionRequest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Sequence</code></TD>
+ * </TR>
+ *
+ * </TABLE>
+ */
+ private static final Class<?>[] VALUE_CLASSES = new Class[15];
+
+ static {
+ VALUE_CLASSES[0] = null; // not used
+ VALUE_CLASSES[1] = String[].class; // EMailAddress
+ VALUE_CLASSES[2] = String[].class; // UnstructuredName
+ VALUE_CLASSES[3] = ObjectIdentifier.class; // ContentType
+ VALUE_CLASSES[4] = byte[].class; // MessageDigest (byte[])
+ VALUE_CLASSES[5] = Date.class; // SigningTime
+ VALUE_CLASSES[6] = SignerInfo[].class; // Countersignature
+ VALUE_CLASSES[7] = String.class; // ChallengePassword
+ VALUE_CLASSES[8] = String[].class; // UnstructuredAddress
+ VALUE_CLASSES[9] = null; // ExtendedCertificateAttributes
+
+ VALUE_CLASSES[10] = null; // IssuerAndSerialNumber
+ VALUE_CLASSES[11] = null; // PasswordCheck
+ VALUE_CLASSES[12] = null; // PublicKey
+ VALUE_CLASSES[13] = null; // SigningDescription
+ VALUE_CLASSES[14] = CertificateExtensions.class; // ExtensionRequest
+ }
+
+ /**
+ * Array indicating which PKCS9 attributes are single-valued,
+ * by index in <code>PKCS9_OIDS</code>.
+ */
+ private static final boolean[] SINGLE_VALUED =
+ { false,
+ false, // EMailAddress
+ false, // UnstructuredName
+ true, // ContentType
+ true, // MessageDigest
+ true, // SigningTime
+ false, // Countersignature
+ true, // ChallengePassword
+ false, // UnstructuredAddress
+ false, // ExtendedCertificateAttributes
+
+ true, // IssuerAndSerialNumber
+ true, // PasswordCheck
+ true, // PublicKey
+ true, // SigningDescription
+ true // ExtensionRequest
+ };
+
+ /**
+ * The OID of this attribute is <code>PKCS9_OIDS[index]</code>.
+ */
+ private int index;
+
+ /**
+ * Value set of this attribute. Its class is given by <code>VALUE_CLASSES[index]</code>.
+ */
+ private Object value;
+
+ /**
+ * Construct an attribute object from the attribute's OID and
+ * value. If the attribute is single-valued, provide only one
+ * value. If the attribute is
+ * multiple-valued, provide an array containing all the values.
+ * Arrays of length zero are accepted, though probably useless.
+ *
+ * <P>
+ * The following table gives the class that <code>value</code> must have for a given attribute.
+ *
+ * <P>
+ * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
+ *
+ * <TR>
+ * <TH>OID</TH>
+ * <TH>Attribute Type Name</TH>
+ * <TH>Kind</TH>
+ * <TH>Value Class</TH>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.1</TD>
+ * <TD>EmailAddress</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.2</TD>
+ * <TD>UnstructuredName</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.3</TD>
+ * <TD>ContentType</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>ObjectIdentifier</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.4</TD>
+ * <TD>MessageDigest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>byte[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.5</TD>
+ * <TD>SigningTime</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Date</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.6</TD>
+ * <TD>Countersignature</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>SignerInfo[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.7</TD>
+ * <TD>ChallengePassword</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.8</TD>
+ * <TD>UnstructuredAddress</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.9</TD>
+ * <TD>ExtendedCertificateAttributes</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.10</TD>
+ * <TD>IssuerAndSerialNumber</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.11</TD>
+ * <TD>PasswordCheck</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.12</TD>
+ * <TD>PublicKey</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.13</TD>
+ * <TD>SigningDescription</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.14</TD>
+ * <TD>ExtensionRequest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Sequence</code></TD>
+ * </TR>
+ *
+ * </TABLE>
+ */
+ public PKCS9Attribute(ObjectIdentifier oid, Object value)
+ throws IllegalArgumentException {
+
+ init(oid, value);
+ }
+
+ /**
+ * Construct an attribute object from the attribute's name and
+ * value. If the attribute is single-valued, provide only one
+ * value. If the attribute is
+ * multiple-valued, provide an array containing all the values.
+ * Arrays of length zero are accepted, though probably useless.
+ *
+ * <P>
+ * The following table gives the class that <code>value</code> must have for a given attribute. Reasonable variants
+ * of these attributes are accepted; in particular, case does not matter.
+ *
+ * <P>
+ * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
+ *
+ * <TR>
+ * <TH>OID</TH>
+ * <TH>Attribute Type Name</TH>
+ * <TH>Kind</TH>
+ * <TH>Value Class</TH>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.1</TD>
+ * <TD>EmailAddress</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.2</TD>
+ * <TD>UnstructuredName</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.3</TD>
+ * <TD>ContentType</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>ObjectIdentifier</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.4</TD>
+ * <TD>MessageDigest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>byte[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.5</TD>
+ * <TD>SigningTime</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Date</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.6</TD>
+ * <TD>Countersignature</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>SignerInfo[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.7</TD>
+ * <TD>ChallengePassword</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.8</TD>
+ * <TD>UnstructuredAddress</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.9</TD>
+ * <TD>ExtendedCertificateAttributes</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.10</TD>
+ * <TD>IssuerAndSerialNumber</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.11</TD>
+ * <TD>PasswordCheck</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.12</TD>
+ * <TD>PublicKey</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.13</TD>
+ * <TD>SigningDescription</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.14</TD>
+ * <TD>ExtensionRequest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Sequence</code></TD>
+ * </TR>
+ *
+ * </TABLE>
+ *
+ * @exception IllegalArgumentException
+ * if the <code>name</code> is not recognized of the <code>value</code> has the wrong type.
+ */
+ public PKCS9Attribute(String name, Object value)
+ throws IllegalArgumentException {
+ ObjectIdentifier oid = getOID(name);
+
+ if (oid == null)
+ throw new IllegalArgumentException(
+ "Unrecognized attribute name " + name +
+ " constructing PKCS9Attribute.");
+
+ init(oid, value);
+ }
+
+ private void init(ObjectIdentifier oid, Object value)
+ throws IllegalArgumentException {
+
+ index = indexOf(oid, PKCS9_OIDS, 1);
+
+ if (index == -1)
+ throw new IllegalArgumentException(
+ "Unsupported OID " + oid +
+ " constructing PKCS9Attribute.");
+
+ if (!VALUE_CLASSES[index].isInstance(value))
+ throw new IllegalArgumentException(
+ "Wrong value class " +
+ " for attribute " + oid +
+ " constructing PKCS9Attribute; was " +
+ value.getClass().toString() + ", should be " +
+ VALUE_CLASSES[index].toString());
+
+ this.value = value;
+ }
+
+ /**
+ * Construct a PKCS9Attribute from its encoding on an input
+ * stream.
+ *
+ * @exception IOException on parsing error.
+ */
+ public PKCS9Attribute(DerValue derVal) throws IOException {
+
+ decode(derVal);
+ }
+
+ /**
+ * Decode a PKCS9 attribute.
+ *
+ * @param val
+ * the DerValue representing the DER encoding of the attribute.
+ */
+ private void decode(DerValue derVal) throws IOException {
+ DerInputStream derIn = new DerInputStream(derVal.toByteArray());
+ DerValue[] val = derIn.getSequence(2);
+
+ if (derIn.available() != 0)
+ throw new IOException("Excess data parsing PKCS9Attribute");
+
+ if (val.length != 2)
+ throw new IOException("PKCS9Attribute doesn't have two components");
+
+ DerValue[] elems;
+
+ // get the oid
+ ObjectIdentifier oid = val[0].getOID();
+
+ index = indexOf(oid, PKCS9_OIDS, 1);
+ Byte tag;
+
+ if (index == -1)
+ throw new IOException("Invalid OID for PKCS9 attribute: " +
+ oid);
+
+ elems = new DerInputStream(val[1].toByteArray()).getSet(1);
+
+ // check single valued have only one value
+ if (SINGLE_VALUED[index] && elems.length > 1)
+ throwSingleValuedException();
+
+ // check for illegal element tags
+ for (int i = 0; i < elems.length; i++) {
+ tag = Byte.valueOf(elems[i].tag);
+
+ if (indexOf(tag, PKCS9_VALUE_TAGS[index], 0) == -1)
+ throwTagException(tag);
+ }
+
+ switch (index) {
+ case 1: // email address
+ case 2: // unstructured name
+ case 8: // unstructured address
+ { // open scope
+ String[] values = new String[elems.length];
+
+ for (int i = 0; i < elems.length; i++)
+ values[i] = elems[i].getAsString();
+ value = values;
+ } // close scope
+ break;
+
+ case 3: // content type
+ value = elems[0].getOID();
+ break;
+
+ case 4: // message digest
+ value = elems[0].getOctetString();
+ break;
+
+ case 5: // signing time
+ value = (new DerInputStream(elems[0].toByteArray())).getUTCTime();
+ break;
+
+ case 6: // countersignature
+ { // open scope
+ SignerInfo[] values = new SignerInfo[elems.length];
+ for (int i = 0; i < elems.length; i++)
+ values[i] =
+ new SignerInfo(elems[i].toDerInputStream());
+ value = values;
+ } // close scope
+ break;
+
+ case 7: // challenge password
+ value = elems[0].getAsString();
+ break;
+
+ case 9: // extended-certificate attribute -- not
+ // supported
+ throw new IOException("PKCS9 extended-certificate " +
+ "attribute not supported.");
+
+ case 10: // IssuerAndSerialNumber attribute -- not
+ // supported
+ throw new IOException("PKCS9 IssuerAndSerialNumber " +
+ "attribute not supported.");
+
+ case 11: // passwordCheck attribute -- not
+ // supported
+ throw new IOException("PKCS9 passwordCheck " +
+ "attribute not supported.");
+ case 12: // PublicKey attribute -- not
+ // supported
+ throw new IOException("PKCS9 PublicKey " +
+ "attribute not supported.");
+ case 13: // SigningDescription attribute -- not
+ // supported
+ throw new IOException("PKCS9 SigningDescription " +
+ "attribute not supported.");
+ case 14: // ExtensionRequest attribute
+ value =
+ new CertificateExtensions(elems[0].toDerInputStream());
+
+ // break unnecessary
+
+ default: // can't happen
+ }
+
+ }
+
+ /**
+ * Write the DER encoding of this attribute to an output stream.
+ *
+ * <P>
+ * N.B.: This method always encodes values of ChallengePassword and UnstructuredAddress attributes as ASN.1
+ * <code>PrintableString</code>s, without checking whether they should be encoded as <code>T61String</code>s.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ DerOutputStream temp = new DerOutputStream();
+ temp.putOID(getOID());
+ switch (index) {
+ case 1: // email address
+ case 2: // unstructured name
+ { // open scope
+ String[] values = (String[]) value;
+ DerOutputStream[] temps = new
+ DerOutputStream[values.length];
+
+ for (int i = 0; i < values.length; i++) {
+ temps[i] = new DerOutputStream();
+
+ temps[i].putIA5String(values[i]);
+ }
+ temp.putOrderedSetOf(DerValue.tag_Set, temps);
+ } // close scope
+ break;
+
+ case 3: // content type
+ {
+ DerOutputStream temp2 = new DerOutputStream();
+ temp2.putOID((ObjectIdentifier) value);
+ temp.write(DerValue.tag_Set, temp2.toByteArray());
+ }
+ break;
+
+ case 4: // message digest
+ {
+ DerOutputStream temp2 = new DerOutputStream();
+ temp2.putOctetString((byte[]) value);
+ temp.write(DerValue.tag_Set, temp2.toByteArray());
+ }
+ break;
+
+ case 5: // signing time
+ {
+ DerOutputStream temp2 = new DerOutputStream();
+ temp2.putUTCTime((Date) value);
+ temp.write(DerValue.tag_Set, temp2.toByteArray());
+ }
+ break;
+
+ case 6: // countersignature
+ temp.putOrderedSetOf(DerValue.tag_Set, (DerEncoder[]) value);
+ break;
+
+ case 7: // challenge password
+ {
+ DerOutputStream temp2 = new DerOutputStream();
+ temp2.putPrintableString((String) value);
+ temp.write(DerValue.tag_Set, temp2.toByteArray());
+ }
+ break;
+
+ case 8: // unstructured address
+ { // open scope
+ String[] values = (String[]) value;
+ DerOutputStream[] temps = new
+ DerOutputStream[values.length];
+
+ for (int i = 0; i < values.length; i++) {
+ temps[i] = new DerOutputStream();
+
+ temps[i].putPrintableString(values[i]);
+ }
+ temp.putOrderedSetOf(DerValue.tag_Set, temps);
+ } // close scope
+ break;
+
+ case 9: // extended-certificate attribute -- not
+ // supported
+ throw new IOException("PKCS9 extended-certificate " +
+ "attribute not supported.");
+
+ case 10: // IssuerAndSerialNumber attribute -- not
+ // supported
+ throw new IOException("PKCS9 IssuerAndSerialNumber " +
+ "attribute not supported.");
+
+ case 11: // passwordCheck attribute -- not
+ // supported
+ throw new IOException("PKCS9 passwordCheck " +
+ "attribute not supported.");
+ case 12: // PublicKey attribute -- not
+ // supported
+ throw new IOException("PKCS9 PublicKey " +
+ "attribute not supported.");
+ case 13: // SigningDescription attribute -- not
+ // supported
+ throw new IOException("PKCS9 SigningDescription " +
+ "attribute not supported.");
+ case 14: // ExtensionRequest attribute
+ try {
+ DerOutputStream temp2 = new DerOutputStream();
+ //temp2.putSequence((CertificateExtensions) value);
+ ((CertificateExtensions) value).encode(temp2);
+ temp.write(DerValue.tag_Sequence, temp2.toByteArray());
+ } catch (CertificateException e) {
+ throw new IOException("PKCS9 extension attributes not encoded");
+ }
+
+ // break unnecessary
+ default: // can't happen
+ }
+
+ DerOutputStream derOut = new DerOutputStream();
+ derOut.write(DerValue.tag_Sequence, temp.toByteArray());
+
+ out.write(derOut.toByteArray());
+
+ }
+
+ /**
+ * Get the value of this attribute. If the attribute is
+ * single-valued, return just the one value. If the attribute is
+ * multiple-valued, return an array containing all the values.
+ * It is possible for this array to be of length 0.
+ *
+ * <P>
+ * The following table gives the class of the value returned, depending on the type of this attribute.
+ *
+ * <P>
+ * <TABLE BORDER CELLPADDING=8 ALIGN=CENTER>
+ *
+ * <TR>
+ * <TH>OID</TH>
+ * <TH>Attribute Type Name</TH>
+ * <TH>Kind</TH>
+ * <TH>Value Class</TH>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.1</TD>
+ * <TD>EmailAddress</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.2</TD>
+ * <TD>UnstructuredName</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.3</TD>
+ * <TD>ContentType</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>ObjectIdentifier</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.4</TD>
+ * <TD>MessageDigest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>byte[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.5</TD>
+ * <TD>SigningTime</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Date</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.6</TD>
+ * <TD>Countersignature</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD><code>SignerInfo[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.7</TD>
+ * <TD>ChallengePassword</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.8</TD>
+ * <TD>UnstructuredAddress</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>String[]</code></TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.9</TD>
+ * <TD>ExtendedCertificateAttributes</TD>
+ * <TD>Multiple-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.10</TD>
+ * <TD>IssuerAndSerialNumber</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.11</TD>
+ * <TD>PasswordCheck</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.12</TD>
+ * <TD>PublicKey</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.13</TD>
+ * <TD>SigningDescription</TD>
+ * <TD>Single-valued</TD>
+ * <TD>(not supported)</TD>
+ * </TR>
+ *
+ * <TR>
+ * <TD>1.2.840.113549.1.9.14</TD>
+ * <TD>ExtensionRequest</TD>
+ * <TD>Single-valued</TD>
+ * <TD><code>Sequence</code></TD>
+ * </TR>
+ *
+ * </TABLE>
+ *
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Show whether this attribute is single-valued.
+ */
+ public boolean isSingleValued() {
+ return SINGLE_VALUED[index];
+ }
+
+ /**
+ * Return the OID of this attribute.
+ */
+ public ObjectIdentifier getOID() {
+ return PKCS9_OIDS[index];
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (String) OID_NAME_TABLE.get(PKCS9_OIDS[index]);
+ }
+
+ /**
+ * Return the OID for a given attribute name or null if we don't recognize
+ * the name.
+ */
+ public static ObjectIdentifier getOID(String name) {
+ return (ObjectIdentifier) NAME_OID_TABLE.get(name.toLowerCase());
+ }
+
+ /**
+ * Return the attribute name for a given OID or null if we don't recognize
+ * the oid.
+ */
+ public static String getName(ObjectIdentifier oid) {
+ return (String) OID_NAME_TABLE.get(oid);
+ }
+
+ /**
+ * Returns a string representation of this attribute.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer(100);
+
+ buf.append("[");
+
+ buf.append(OID_NAME_TABLE.get(PKCS9_OIDS[index]));
+ buf.append(": ");
+
+ if (SINGLE_VALUED[index]) {
+ if (value instanceof byte[]) { // special case for octet string
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String valuebits = pp.toHexString(((byte[]) value));
+ buf.append(valuebits);
+ } else {
+ buf.append(value.toString());
+ }
+ buf.append("]");
+ return buf.toString();
+ } else { // multiple-valued
+ boolean first = true;
+ Object[] values = (Object[]) value;
+
+ for (int j = 0; j < values.length; j++) {
+ if (first)
+ first = false;
+ else
+ buf.append(", ");
+
+ buf.append(values[j].toString());
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Beginning the search at <code>start</code>, find the first
+ * index <code>i</code> such that <code>a[i] = obj</code>.
+ *
+ * @return the index, if found, and -1 otherwise.
+ */
+ static int indexOf(Object obj, Object[] a, int start) {
+ for (int i = start; i < a.length; i++) {
+ if (obj.equals(a[i]))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Throw an exception when there are multiple values for
+ * a single-valued attribute.
+ */
+ private void throwSingleValuedException() throws IOException {
+ throw new IOException("Single-value attribute " +
+ getOID() + " (" + getName() + ")" +
+ " has multiple values.");
+ }
+
+ /**
+ * Throw an exception when the tag on a value encoding is
+ * wrong for the attribute whose value it is.
+ */
+ private void throwTagException(Byte tag)
+ throws IOException {
+ Byte[] expectedTags = PKCS9_VALUE_TAGS[index];
+ StringBuffer msg = new StringBuffer(100);
+ msg.append("Value of attribute ");
+ msg.append(getOID().toString());
+ msg.append(" (");
+ msg.append(getName());
+ msg.append(") has wrong tag: ");
+ msg.append(tag.toString());
+ msg.append(". Expected tags: ");
+
+ msg.append(expectedTags[0].toString());
+
+ for (int i = 1; i < expectedTags.length; i++) {
+ msg.append(", ");
+ msg.append(expectedTags[i].toString());
+ }
+ msg.append(".");
+ throw new IOException(msg.toString());
+ }
+
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS9Attributes.java b/base/util/src/netscape/security/pkcs/PKCS9Attributes.java
new file mode 100644
index 000000000..485cdded1
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS9Attributes.java
@@ -0,0 +1,312 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Hashtable;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * A set of attributes of class PKCS9Attribute.
+ *
+ * @version 1.2 97/12/10
+ * @author Douglas Hoover
+ */
+public class PKCS9Attributes {
+
+ /**
+ * Attributes in this set indexed by OID.
+ */
+ private final Hashtable<ObjectIdentifier, PKCS9Attribute> attributes = new Hashtable<ObjectIdentifier, PKCS9Attribute>(3);
+
+ /**
+ * The keys of this hashtable are the OIDs of permitted attributes.
+ */
+ private final Hashtable<ObjectIdentifier, ObjectIdentifier> permittedAttributes;
+
+ /**
+ * The DER encoding of this attribute set. The tag byte must be
+ * DerValue.tag_SetOf.
+ */
+ private final byte[] derEncoding;
+
+ /**
+ * Construct a set of PKCS9 Attributes from its
+ * DER encoding on a DerInputStream, accepting only attributes
+ * with OIDs on the given
+ * list. If the array is null, accept all attributes supported by
+ * class PKCS9Attribute.
+ *
+ * @param permittedAttributes
+ * Array of attribute OIDs that will be accepted.
+ * @param buf
+ * the contents of the DER encoding of the attribute set.
+ *
+ * @exception IOException
+ * on i/o error, encoding syntax error, unacceptable or
+ * unsupported attribute, or duplicate attribute.
+ *
+ * @see PKCS9Attribute
+ */
+ public PKCS9Attributes(ObjectIdentifier[] permittedAttributes,
+ DerInputStream in) throws IOException {
+ if (permittedAttributes != null) {
+ this.permittedAttributes =
+ new Hashtable<ObjectIdentifier, ObjectIdentifier>(permittedAttributes.length);
+
+ for (int i = 0; i < permittedAttributes.length; i++)
+ this.permittedAttributes.put(permittedAttributes[i],
+ permittedAttributes[i]);
+ } else {
+ this.permittedAttributes = null;
+ }
+
+ // derEncoding initialized in <code>decode()</code>
+ derEncoding = decode(in);
+ }
+
+ /**
+ * Construct a set of PKCS9 Attributes from its contents of its
+ * DER encoding on a DerInputStream. Accept all attributes
+ * supported by class PKCS9Attribute.
+ *
+ * @exception IOException
+ * on i/o error, encoding syntax error, or unsupported or
+ * duplicate attribute.
+ *
+ * @see PKCS9Attribute
+ */
+ public PKCS9Attributes(DerInputStream in) throws IOException {
+ // anything goes
+ // derEncoding initialized in <code>decode()</code>
+ derEncoding = decode(in);
+ permittedAttributes = null;
+ }
+
+ /**
+ * Construct a set of PKCS9 Attributes from the given array of
+ * PCK9 attributes.
+ * DER encoding on a DerInputStream. All attributes in <code>attribs</code> must be
+ * supported by class PKCS9Attribute.
+ *
+ * @exception IOException
+ * on i/o error, encoding syntax error, or unsupported or
+ * duplicate attribute.
+ *
+ * @see PKCS9Attribute
+ */
+ public PKCS9Attributes(PKCS9Attribute[] attribs)
+ throws IllegalArgumentException, IOException {
+ ObjectIdentifier oid;
+ for (int i = 0; i < attribs.length; i++) {
+ oid = attribs[i].getOID();
+ if (attributes.containsKey(oid))
+ throw new IllegalArgumentException(
+ "PKCSAttribute " + attribs[i].getOID() +
+ " duplicated while constructing " +
+ "PKCS9Attributes.");
+
+ attributes.put(oid, attribs[i]);
+ }
+ derEncoding = generateDerEncoding();
+ permittedAttributes = null;
+ }
+
+ /**
+ * Decode this set of PKCS9 attribute set from the contents of its
+ * DER encoding.
+ *
+ * @param buf
+ * the contents of the DER encoding of the attribute set.
+ *
+ * @exception IOException
+ * on i/o error, encoding syntax error, unacceptable or
+ * unsupported attribute, or duplicate attribute.
+ */
+ private byte[] decode(DerInputStream in) throws IOException {
+
+ DerValue val = in.getDerValue();
+
+ // save the DER encoding with its proper tag byte.
+ byte[] derEncoding = val.toByteArray();
+ derEncoding[0] = DerValue.tag_SetOf;
+
+ DerInputStream derIn = new DerInputStream(derEncoding);
+ DerValue[] derVals = derIn.getSet(3, true);
+
+ PKCS9Attribute attrib;
+ ObjectIdentifier oid;
+
+ for (int i = 0; i < derVals.length; i++) {
+ attrib = new PKCS9Attribute(derVals[i]);
+ oid = attrib.getOID();
+
+ if (attributes.get(oid) != null)
+ throw new IOException("Duplicate PKCS9 attribute: " + oid);
+
+ if (permittedAttributes != null &&
+ !permittedAttributes.containsKey(oid))
+ throw new IOException("Attribute " + oid +
+ " not permitted in this attribute set");
+
+ attributes.put(oid, attrib);
+ }
+ return derEncoding;
+
+ }
+
+ /**
+ * Put the DER encoding of this PKCS9 attribute set on an
+ * DerOutputStream, tagged with the given implicit tag.
+ *
+ * @param tag the implicit tag to use in the DER encoding.
+ * @param out the output stream on which to put the DER encoding.
+ *
+ * @exception IOException on output error.
+ */
+ public void encode(byte tag, OutputStream out) throws IOException {
+ out.write(tag);
+ out.write(derEncoding, 1, derEncoding.length - 1);
+ }
+
+ private byte[] generateDerEncoding() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ Object[] attribVals = attributes.values().toArray();
+
+ out.putOrderedSetOf(DerValue.tag_SetOf,
+ castToDerEncoder(attribVals));
+ return out.toByteArray();
+ }
+
+ /**
+ * Return the DER encoding of this attribute set, tagged with
+ * DerValue.tag_SetOf.
+ */
+ public byte[] getDerEncoding() throws IOException {
+ return (byte[]) derEncoding.clone();
+
+ }
+
+ /**
+ * Get an attribute from this set.
+ */
+ public PKCS9Attribute getAttribute(ObjectIdentifier oid) {
+ return attributes.get(oid);
+ }
+
+ /**
+ * Get an attribute from this set.
+ */
+ public PKCS9Attribute getAttribute(String name) {
+ return attributes.get(PKCS9Attribute.getOID(name));
+ }
+
+ /**
+ * Get an array of all attributes in this set, in order of OID.
+ */
+ public PKCS9Attribute[] getAttributes() {
+ PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()];
+
+ int j = 0;
+ for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length &&
+ j < attribs.length; i++) {
+ attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);
+
+ if (attribs[j] != null)
+ j++;
+ }
+ return attribs;
+ }
+
+ /**
+ * Get an attribute value by OID.
+ */
+ public Object getAttributeValue(ObjectIdentifier oid)
+ throws IOException {
+ try {
+ Object value = getAttribute(oid).getValue();
+ return value;
+ } catch (NullPointerException ex) {
+ throw new IOException("No value found for attribute " + oid);
+ }
+
+ }
+
+ /**
+ * Get an attribute value by type name.
+ */
+ public Object getAttributeValue(String name) throws IOException {
+ ObjectIdentifier oid = PKCS9Attribute.getOID(name);
+
+ if (oid == null)
+ throw new IOException("Attribute name " + name +
+ " not recognized or not supported.");
+
+ return getAttributeValue(oid);
+ }
+
+ /**
+ * Returns the PKCS9 block in a printable string form.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer(200);
+ buf.append("PKCS9 Attributes: [\n\t");
+
+ PKCS9Attribute value;
+
+ boolean first = true;
+ for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) {
+ value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);
+
+ if (value == null)
+ continue;
+
+ // we have a value; print it
+ if (first)
+ first = false;
+ else
+ buf.append(";\n\t");
+
+ buf.append(value.toString());
+ }
+
+ buf.append("\n\t] (end PKCS9 Attributes)");
+
+ return buf.toString();
+ }
+
+ /**
+ * Cast an object array whose components are <code>DerEncoder</code>s to <code>DerEncoder[]</code>.
+ */
+ static DerEncoder[] castToDerEncoder(Object[] objs) {
+
+ DerEncoder[] encoders = new DerEncoder[objs.length];
+
+ for (int i = 0; i < encoders.length; i++)
+ encoders[i] = (DerEncoder) objs[i];
+
+ return encoders;
+ }
+
+}
diff --git a/base/util/src/netscape/security/pkcs/ParsingException.java b/base/util/src/netscape/security/pkcs/ParsingException.java
new file mode 100644
index 000000000..88e91a8db
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/ParsingException.java
@@ -0,0 +1,35 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+
+public class ParsingException extends IOException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8135726194372647410L;
+
+ public ParsingException() {
+ super();
+ }
+
+ public ParsingException(String s) {
+ super(s);
+ }
+}
diff --git a/base/util/src/netscape/security/pkcs/SignerInfo.java b/base/util/src/netscape/security/pkcs/SignerInfo.java
new file mode 100644
index 000000000..adb0115cc
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/SignerInfo.java
@@ -0,0 +1,347 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X500Name;
+
+/**
+ * A SignerInfo, as defined in PKCS#7's signedData type.
+ *
+ * @author Benjamin Renaud
+ * @version 1.27 97/12/10
+ */
+public class SignerInfo implements DerEncoder {
+
+ BigInt version;
+ X500Name issuerName;
+ BigInt certificateSerialNumber;
+ AlgorithmId digestAlgorithmId;
+ AlgorithmId digestEncryptionAlgorithmId;
+ byte[] encryptedDigest;
+
+ PKCS9Attributes authenticatedAttributes;
+ PKCS9Attributes unauthenticatedAttributes;
+
+ public SignerInfo(X500Name issuerName,
+ BigInt serial,
+ AlgorithmId digestAlgorithmId,
+ AlgorithmId digestEncryptionAlgorithmId,
+ byte[] encryptedDigest) {
+ this.version = new BigInt(1);
+ this.issuerName = issuerName;
+ this.certificateSerialNumber = serial;
+ this.digestAlgorithmId = digestAlgorithmId;
+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
+ this.encryptedDigest = encryptedDigest;
+ }
+
+ public SignerInfo(X500Name issuerName,
+ BigInt serial,
+ AlgorithmId digestAlgorithmId,
+ PKCS9Attributes authenticatedAttributes,
+ AlgorithmId digestEncryptionAlgorithmId,
+ byte[] encryptedDigest,
+ PKCS9Attributes unauthenticatedAttributes) {
+ this.version = new BigInt(1);
+ this.issuerName = issuerName;
+ this.certificateSerialNumber = serial;
+ this.digestAlgorithmId = digestAlgorithmId;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ public SignerInfo(DerInputStream derin)
+ throws IOException, ParsingException {
+
+ // version
+ version = derin.getInteger();
+
+ // issuerAndSerialNumber
+ DerValue[] issuerAndSerialNumber = derin.getSequence(2);
+ byte[] issuerBytes = issuerAndSerialNumber[0].toByteArray();
+ issuerName = new X500Name(new DerValue(DerValue.tag_Sequence,
+ issuerBytes));
+ certificateSerialNumber = issuerAndSerialNumber[1].getInteger();
+
+ // digestAlgorithmId
+ DerValue tmp = derin.getDerValue();
+
+ digestAlgorithmId = AlgorithmId.parse(tmp);
+
+ /*
+ * check if set of auth attributes (implicit tag) is provided
+ * (auth attributes are OPTIONAL)
+ */
+ if ((byte) (derin.peekByte()) == (byte) 0xA0) {
+ authenticatedAttributes = new PKCS9Attributes(derin);
+ }
+
+ // digestEncryptionAlgorithmId - little RSA naming scheme -
+ // signature == encryption...
+ tmp = derin.getDerValue();
+
+ digestEncryptionAlgorithmId = AlgorithmId.parse(tmp);
+
+ // encryptedDigest
+ encryptedDigest = derin.getOctetString();
+
+ /*
+ * check if set of unauth attributes (implicit tag) is provided
+ * (unauth attributes are OPTIONAL)
+ */
+ if (derin.available() != 0 && (byte) (derin.peekByte()) == (byte) 0xA1) {
+ unauthenticatedAttributes = new PKCS9Attributes(derin);
+ }
+
+ // all done
+ if (derin.available() != 0) {
+ throw new ParsingException("extra data at the end");
+ }
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+
+ derEncode(out);
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ seq.putInteger(version);
+ DerOutputStream issuerAndSerialNumber = new DerOutputStream();
+ issuerName.encode(issuerAndSerialNumber);
+ issuerAndSerialNumber.putInteger(certificateSerialNumber);
+ seq.write(DerValue.tag_Sequence, issuerAndSerialNumber);
+
+ digestAlgorithmId.encode(seq);
+
+ // encode authenticated attributes if there are any
+ if (authenticatedAttributes != null)
+ authenticatedAttributes.encode((byte) 0xA0, seq);
+
+ digestEncryptionAlgorithmId.encode(seq);
+
+ seq.putOctetString(encryptedDigest);
+
+ // encode unauthenticated attributes if there are any
+ if (unauthenticatedAttributes != null)
+ unauthenticatedAttributes.encode((byte) 0xA1, seq);
+
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.write(DerValue.tag_Sequence, seq);
+
+ out.write(tmp.toByteArray());
+ }
+
+ public X509Certificate getCertificate(PKCS7 block)
+ throws IOException {
+ return block.getCertificate(certificateSerialNumber, issuerName);
+ }
+
+ /* Returns null if verify fails, this signerInfo if
+ verify succeeds. */
+ SignerInfo verify(PKCS7 block, byte[] data)
+ throws NoSuchAlgorithmException, SignatureException {
+
+ try {
+
+ ContentInfo content = block.getContentInfo();
+ if (data == null) {
+ data = content.getContentBytes();
+ }
+
+ String digestAlgname =
+ getDigestAlgorithmId().getName();
+
+ byte[] dataSigned;
+
+ // if there are authenticate attributes, get the message
+ // digest and compare it with the digest of data
+ if (authenticatedAttributes == null) {
+ dataSigned = data;
+ } else {
+
+ // first, check content type
+ ObjectIdentifier contentType = (ObjectIdentifier)
+ authenticatedAttributes.getAttributeValue(
+ PKCS9Attribute.CONTENT_TYPE_OID);
+ if (contentType == null ||
+ !contentType.equals(content.contentType))
+ return null; // contentType does not match, bad SignerInfo
+
+ // now, check message digest
+ byte[] messageDigest = (byte[])
+ authenticatedAttributes.getAttributeValue(
+ PKCS9Attribute.MESSAGE_DIGEST_OID);
+
+ if (messageDigest == null) // fail if there is no message digest
+ return null;
+
+ MessageDigest md = MessageDigest.getInstance(digestAlgname);
+ byte[] computedMessageDigest = md.digest(data);
+
+ if (messageDigest.length != computedMessageDigest.length)
+ return null;
+ for (int i = 0; i < messageDigest.length; i++) {
+ if (messageDigest[i] != computedMessageDigest[i])
+ return null;
+ }
+
+ // message digest attribute matched
+ // digest of original data
+
+ // the data actually signed is the DER encoding of
+ // the authenticated attributes (tagged with
+ // the "SET OF" tag, not 0xA0).
+ dataSigned = authenticatedAttributes.getDerEncoding();
+ }
+
+ // put together digest algorithm and encryption algorithm
+ // to form signing algorithm
+ String encryptionAlgname =
+ getDigestEncryptionAlgorithmId().getName();
+
+ String algname;
+ if (encryptionAlgname.equals("DSA") ||
+ encryptionAlgname.equals("SHA1withDSA")) {
+ algname = "DSA";
+ } else {
+ algname = digestAlgname + "/" + encryptionAlgname;
+ }
+
+ Signature sig = Signature.getInstance(algname);
+ X509Certificate cert = getCertificate(block);
+
+ if (cert == null) {
+ return null;
+ }
+
+ PublicKey key = cert.getPublicKey();
+ sig.initVerify(key);
+
+ sig.update(dataSigned);
+
+ if (sig.verify(encryptedDigest)) {
+ return this;
+ }
+
+ } catch (IOException e) {
+ throw new SignatureException("IO error verifying signature:\n" +
+ e.getMessage());
+
+ } catch (InvalidKeyException e) {
+ throw new SignatureException("InvalidKey: " + e.getMessage());
+
+ }
+ return null;
+ }
+
+ /* Verify the content of the pkcs7 block. */
+ SignerInfo verify(PKCS7 block)
+ throws NoSuchAlgorithmException, SignatureException {
+ return verify(block, null);
+ }
+
+ public BigInt getVersion() {
+ return version;
+ }
+
+ public X500Name getIssuerName() {
+ return issuerName;
+ }
+
+ public BigInt getCertificateSerialNumber() {
+ return certificateSerialNumber;
+ }
+
+ public AlgorithmId getDigestAlgorithmId() {
+ return digestAlgorithmId;
+ }
+
+ public PKCS9Attributes getAuthenticatedAttributes() {
+ return authenticatedAttributes;
+ }
+
+ public AlgorithmId getDigestEncryptionAlgorithmId() {
+ return digestEncryptionAlgorithmId;
+ }
+
+ public byte[] getEncryptedDigest() {
+ return encryptedDigest;
+ }
+
+ public PKCS9Attributes getUnauthenticatedAttributes() {
+ return unauthenticatedAttributes;
+ }
+
+ public String toString() {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String digestbits = pp.toHexString(encryptedDigest);
+
+ String out = "";
+
+ out += "Signer Info for (issuer): " + issuerName + "\n";
+ out += "\tversion: " + version + "\n";
+ out += "\tcertificateSerialNumber: " + certificateSerialNumber +
+ "\n";
+ out += "\tdigestAlgorithmId: " + digestAlgorithmId + "\n";
+ if (authenticatedAttributes != null) {
+ out += "\tauthenticatedAttributes: " + authenticatedAttributes +
+ "\n";
+ }
+ out += "\tdigestEncryptionAlgorithmId: " + digestEncryptionAlgorithmId +
+ "\n";
+
+ out += "\tencryptedDigest: " + "\n" +
+ digestbits + "\n";
+ if (unauthenticatedAttributes != null) {
+ out += "\tunauthenticatedAttributes: " +
+ unauthenticatedAttributes + "\n";
+ }
+ return out;
+ }
+
+}
diff --git a/base/util/src/netscape/security/provider/CMS.java b/base/util/src/netscape/security/provider/CMS.java
new file mode 100644
index 000000000..4a4f150ab
--- /dev/null
+++ b/base/util/src/netscape/security/provider/CMS.java
@@ -0,0 +1,52 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.AccessController;
+import java.security.Provider;
+
+/**
+ * The CMS Security Provider.
+ */
+
+public final class CMS extends Provider {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1065207998900104219L;
+ private static final String INFO = "CMS " +
+ "(DSA key/parameter generation; DSA signing; " +
+ "SHA-1, MD5 digests; SecureRandom; X.509 certificates)";
+
+ public CMS() {
+ /* We are the SUN provider */
+ super("CMS", 1.0, INFO);
+
+ AccessController.doPrivileged(new java.security.PrivilegedAction<Object>() {
+ public Object run() {
+ /*
+ * Certificates
+ */
+ put("CertificateFactory.X.509", "netscape.security.provider.X509CertificateFactory");
+ put("Alg.Alias.CertificateFactory.X.509", "X.509");
+ return null;
+ }
+ });
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSA.java b/base/util/src/netscape/security/provider/DSA.java
new file mode 100644
index 000000000..262095576
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSA.java
@@ -0,0 +1,660 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.DSAParams;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * The Digital Signature Standard (using the Digital Signature
+ * Algorithm), as described in fips186 of the National Instute of
+ * Standards and Technology (NIST), using fips180-1 (SHA-1).
+ *
+ * @author Benjamin Renaud
+ *
+ * @version 1.86, 97/09/17
+ *
+ * @see DSAPublicKey
+ * @see DSAPrivateKey
+ */
+
+public final class DSA extends Signature {
+
+ /* Are we debugging? */
+ private static boolean debug = false;
+
+ /* The parameter object */
+ private DSAParams params;
+
+ /* algorithm parameters */
+ private BigInteger presetP, presetQ, presetG;
+
+ /* The public key, if any */
+ private BigInteger presetY;
+
+ /* The private key, if any */
+ private BigInteger presetX;
+
+ /* The SHA hash for the data */
+ private MessageDigest dataSHA;
+
+ /* The random seed used to generate k */
+ private int[] Kseed;
+
+ /* The random seed used to generate k (specified by application) */
+ private byte[] KseedAsByteArray;
+
+ /*
+ * The random seed used to generate k
+ * (prevent the same Kseed from being used twice in a row
+ */
+ private int[] previousKseed;
+
+ /* The RNG used to output a seed for generating k */
+ private SecureRandom signingRandom;
+
+ /**
+ * Construct a blank DSA object. It can generate keys, but must be
+ * initialized before being usable for signing or verifying.
+ */
+ public DSA() throws NoSuchAlgorithmException {
+ super("SHA/DSA");
+ dataSHA = MessageDigest.getInstance("SHA");
+ }
+
+ /**
+ * Initialize the DSA object with a DSA private key.
+ *
+ * @param privateKey the DSA private key
+ *
+ * @exception InvalidKeyException if the key is not a valid DSA private
+ * key.
+ */
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {
+ throw new InvalidKeyException("not a DSA private key: " +
+ privateKey);
+ }
+ java.security.interfaces.DSAPrivateKey priv =
+ (java.security.interfaces.DSAPrivateKey) privateKey;
+
+ this.presetX = priv.getX();
+ initialize(priv.getParams());
+ }
+
+ /**
+ * Initialize the DSA object with a DSA public key.
+ *
+ * @param publicKey the DSA public key.
+ *
+ * @exception InvalidKeyException if the key is not a valid DSA public
+ * key.
+ */
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {
+ throw new InvalidKeyException("not a DSA public key: " +
+ publicKey);
+ }
+ java.security.interfaces.DSAPublicKey pub =
+ (java.security.interfaces.DSAPublicKey) publicKey;
+ this.presetY = pub.getY();
+ initialize(pub.getParams());
+ }
+
+ private void initialize(DSAParams params) {
+ dataSHA.reset();
+ setParams(params);
+ }
+
+ /**
+ * Sign all the data thus far updated. The signature is formatted
+ * according to the Canonical Encoding Rules, returned as a DER
+ * sequence of Integer, r and s.
+ *
+ * @return a signature block formatted according to the Canonical
+ * Encoding Rules.
+ *
+ * @exception SignatureException if the signature object was not
+ * properly initialized, or if another exception occurs.
+ *
+ * @see netscape.security.provider.DSA#engineUpdate
+ * @see netscape.security.provider.DSA#engineVerify
+ */
+ protected byte[] engineSign() throws SignatureException {
+ BigInteger k = generateK(presetQ);
+ BigInteger r = generateR(presetP, presetQ, presetG, k);
+ BigInteger s = generateS(presetX, presetQ, r, k);
+
+ // got to convert to BigInt...
+ BigInt rAsBigInt = new BigInt(r.toByteArray());
+ BigInt sAsBigInt = new BigInt(s.toByteArray());
+
+ try {
+ DerOutputStream outseq = new DerOutputStream(100);
+ outseq.putInteger(rAsBigInt);
+ outseq.putInteger(sAsBigInt);
+ DerValue result = new DerValue(DerValue.tag_Sequence,
+ outseq.toByteArray());
+
+ return result.toByteArray();
+
+ } catch (IOException e) {
+ throw new SignatureException("error encoding signature");
+ }
+ }
+
+ /**
+ * Verify all the data thus far updated.
+ *
+ * @param signature the alledged signature, encoded using the
+ * Canonical Encoding Rules, as a sequence of integers, r and s.
+ *
+ * @exception SignatureException if the signature object was not
+ * properly initialized, or if another exception occurs.
+ *
+ * @see netscape.security.provider.DSA#engineUpdate
+ * @see netscape.security.provider.DSA#engineSign
+ */
+ protected boolean engineVerify(byte[] signature)
+ throws SignatureException {
+
+ BigInteger r = null;
+ BigInteger s = null;
+ // first decode the signature.
+ try {
+ DerInputStream in = new DerInputStream(signature);
+ DerValue[] values = in.getSequence(2);
+
+ r = values[0].getInteger().toBigInteger();
+ s = values[1].getInteger().toBigInteger();
+
+ } catch (IOException e) {
+ throw new SignatureException("invalid encoding for signature");
+ }
+ BigInteger w = generateW(presetP, presetQ, presetG, s);
+ BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
+
+ return v.equals(r);
+ }
+
+ BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
+ BigInteger k) {
+ BigInteger temp = g.modPow(k, p);
+ return temp.remainder(q);
+
+ }
+
+ BigInteger generateS(BigInteger x, BigInteger q,
+ BigInteger r, BigInteger k) {
+
+ byte[] s2 = dataSHA.digest();
+ BigInteger temp = new BigInteger(1, s2);
+ BigInteger k1 = k.modInverse(q);
+
+ BigInteger s = x.multiply(r);
+ s = temp.add(s);
+ s = k1.multiply(s);
+ return s.remainder(q);
+ }
+
+ BigInteger generateW(BigInteger p, BigInteger q,
+ BigInteger g, BigInteger s) {
+ return s.modInverse(q);
+ }
+
+ BigInteger generateV(BigInteger y, BigInteger p,
+ BigInteger q, BigInteger g,
+ BigInteger w, BigInteger r) {
+
+ byte[] s2 = dataSHA.digest();
+ BigInteger temp = new BigInteger(1, s2);
+
+ temp = temp.multiply(w);
+ BigInteger u1 = temp.remainder(q);
+
+ BigInteger u2 = (r.multiply(w)).remainder(q);
+
+ BigInteger t1 = g.modPow(u1, p);
+ BigInteger t2 = y.modPow(u2, p);
+ BigInteger t3 = t1.multiply(t2);
+ BigInteger t5 = t3.remainder(p);
+ return t5.remainder(q);
+ }
+
+ /*
+ * Please read bug report 4044247 for an alternative, faster,
+ * NON-FIPS approved method to generate K
+ */
+ BigInteger generateK(BigInteger q) {
+
+ BigInteger k = null;
+
+ // The application specified a Kseed for us to use.
+ // Note that we do not allow usage of the same Kseed twice in a row
+ if (Kseed != null && compareSeeds(Kseed, previousKseed) != 0) {
+ k = generateK(Kseed, q);
+ if (k.signum() > 0 && k.compareTo(q) < 0) {
+ previousKseed = new int[Kseed.length];
+ System.arraycopy(Kseed, 0, previousKseed, 0, Kseed.length);
+ return k;
+ }
+ }
+
+ // The application did not specify a Kseed for us to use.
+ // We'll generate a new Kseed by getting random bytes from
+ // a SecureRandom object.
+ SecureRandom random = getSigningRandom();
+
+ while (true) {
+ int[] seed = new int[5];
+
+ for (int i = 0; i < 5; i++)
+ seed[i] = random.nextInt();
+ k = generateK(seed, q);
+ if (k.signum() > 0 && k.compareTo(q) < 0) {
+ previousKseed = new int[seed.length];
+ System.arraycopy(seed, 0, previousKseed, 0, seed.length);
+ return k;
+ }
+ }
+ }
+
+ // Use the application-specified SecureRandom Object if provided.
+ // Otherwise, use our default SecureRandom Object.
+ private SecureRandom getSigningRandom() {
+ if (signingRandom == null) {
+ if (appRandom != null)
+ signingRandom = appRandom;
+ else
+ signingRandom = new SecureRandom();
+ }
+ return signingRandom;
+ }
+
+ /*
+ * return 0 if equal
+ * return 1 if not equal
+ */
+ private int compareSeeds(int[] seed1, int[] seed2) {
+
+ if ((seed1 == null && seed1 == null) ||
+ (seed1 == null && seed2 != null) ||
+ (seed1 != null && seed2 == null) ||
+ seed1.length != seed2.length)
+ return 1;
+
+ for (int i = 0; i < seed1.length; i++) {
+ if (seed1[i] != seed2[i])
+ return 1;
+ }
+
+ return 0;
+
+ }
+
+ /**
+ * Compute k for a DSA signature.
+ *
+ * @param seed the seed for generating k. This seed should be
+ * secure. This is what is refered to as the KSEED in the DSA
+ * specification.
+ *
+ * @param g the g parameter from the DSA key pair.
+ */
+ BigInteger generateK(int[] seed, BigInteger q) {
+
+ // check out t in the spec.
+ int[] t = { 0xEFCDAB89, 0x98BADCFE, 0x10325476,
+ 0xC3D2E1F0, 0x67452301 };
+ //
+ int[] tmp = DSA.SHA_7(seed, t);
+ byte[] tmpBytes = new byte[tmp.length * 4];
+ for (int i = 0; i < tmp.length; i++) {
+ int k = tmp[i];
+ for (int j = 0; j < 4; j++) {
+ tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8)));
+ }
+ }
+ BigInteger k = new BigInteger(1, tmpBytes).mod(q);
+ return k;
+ }
+
+ // Constants for each round
+ private static final int round1_kt = 0x5a827999;
+ private static final int round2_kt = 0x6ed9eba1;
+ private static final int round3_kt = 0x8f1bbcdc;
+ private static final int round4_kt = 0xca62c1d6;
+
+ /**
+ * Computes set 1 thru 7 of SHA-1 on m1.
+ */
+ static int[] SHA_7(int[] m1, int[] h) {
+
+ int[] W = new int[80];
+ System.arraycopy(m1, 0, W, 0, m1.length);
+ int temp = 0;
+
+ for (int t = 16; t <= 79; t++) {
+ temp = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+ W[t] = ((temp << 1) | (temp >>> (32 - 1)));
+ }
+
+ int a = h[0], b = h[1], c = h[2], d = h[3], e = h[4];
+ for (int i = 0; i < 20; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ ((b & c) | ((~b) & d)) + e + W[i] + round1_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 2
+ for (int i = 20; i < 40; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ (b ^ c ^ d) + e + W[i] + round2_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 3
+ for (int i = 40; i < 60; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ ((b & c) | (b & d) | (c & d)) + e + W[i] + round3_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 4
+ for (int i = 60; i < 80; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ (b ^ c ^ d) + e + W[i] + round4_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+ int[] md = new int[5];
+ md[0] = h[0] + a;
+ md[1] = h[1] + b;
+ md[2] = h[2] + c;
+ md[3] = h[3] + d;
+ md[4] = h[4] + e;
+ return md;
+ }
+
+ /**
+ * This implementation recognizes the following parameter:
+ * <dl>
+ *
+ * <dt><tt>Kseed</tt>
+ *
+ * <dd>a byte array.
+ *
+ * </dl>
+ *
+ * @deprecated
+ */
+ protected void engineSetParameter(String key, Object param) {
+
+ if (key.equals("KSEED")) {
+
+ if (param instanceof byte[]) {
+
+ Kseed = byteArray2IntArray((byte[]) param);
+ KseedAsByteArray = (byte[]) param;
+
+ } else {
+ debug("unrecognized param: " + key);
+ throw new InvalidParameterException("Kseed not a byte array");
+ }
+
+ } else {
+ throw new InvalidParameterException("invalid parameter");
+ }
+ }
+
+ /**
+ * Return the value of the requested parameter. Recognized
+ * parameters are:
+ *
+ * <dl>
+ *
+ * <dt><tt>Kseed</tt>
+ *
+ * <dd>a byte array.
+ *
+ * </dl>
+ *
+ * @return the value of the requested parameter.
+ *
+ * @deprecated
+ */
+ protected Object engineGetParameter(String key) {
+ if (key.equals("KSEED")) {
+ return KseedAsByteArray;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Set the algorithm object.
+ */
+ private void setParams(DSAParams params) {
+ this.params = params;
+ this.presetP = params.getP();
+ this.presetQ = params.getQ();
+ this.presetG = params.getG();
+ }
+
+ /**
+ * Update a byte to be signed or verified.
+ *
+ * @param b the byte to updated.
+ */
+ protected void engineUpdate(byte b) {
+ dataSHA.update(b);
+ }
+
+ /**
+ * Update an array of bytes to be signed or verified.
+ *
+ * @param data the bytes to be updated.
+ */
+ protected void engineUpdate(byte[] data, int off, int len) {
+ dataSHA.update(data, off, len);
+ }
+
+ /**
+ * Return a human readable rendition of the engine.
+ */
+ public String toString() {
+ String printable = "DSA Signature";
+ if (presetP != null && presetQ != null && presetG != null) {
+ printable += "\n\tp: " + presetP.toString(16);
+ printable += "\n\tq: " + presetQ.toString(16);
+ printable += "\n\tg: " + presetG.toString(16);
+ } else {
+ printable += "\n\t P, Q or G not initialized.";
+ }
+ if (presetY != null) {
+ printable += "\n\ty: " + presetY.toString(16);
+ }
+ if (presetY == null && presetX == null) {
+ printable += "\n\tUNINIIALIZED";
+ }
+ return printable;
+ }
+
+ /*
+ * Utility routine for converting a byte array into an int array
+ */
+ private int[] byteArray2IntArray(byte[] byteArray) {
+
+ int j = 0;
+ byte[] newBA;
+ int mod = byteArray.length % 4;
+
+ // guarantee that the incoming byteArray is a multiple of 4
+ // (pad with 0's)
+ switch (mod) {
+ case 3:
+ newBA = new byte[byteArray.length + 1];
+ break;
+ case 2:
+ newBA = new byte[byteArray.length + 2];
+ break;
+ case 1:
+ newBA = new byte[byteArray.length + 3];
+ break;
+ default:
+ newBA = new byte[byteArray.length + 0];
+ break;
+ }
+ System.arraycopy(byteArray, 0, newBA, 0, byteArray.length);
+
+ // copy each set of 4 bytes in the byte array into an integer
+ int[] newSeed = new int[newBA.length / 4];
+ for (int i = 0; i < newBA.length; i += 4) {
+ newSeed[j] = newBA[i + 3] & 0xFF;
+ newSeed[j] |= (newBA[i + 2] << 8) & 0xFF00;
+ newSeed[j] |= (newBA[i + 1] << 16) & 0xFF0000;
+ newSeed[j] |= (newBA[i + 0] << 24) & 0xFF000000;
+ j++;
+ }
+
+ return newSeed;
+ }
+
+ /* We include the test vectors from the DSA specification, FIPS
+ 186, and the FIPS 186 Change No 1, which updates the test
+ vector using SHA-1 instead of SHA (for both the G function and
+ the message hash. */
+
+ static void testDSA() throws Exception {
+ PrintStream p = System.out;
+
+ DSA dsa = new DSA();
+ int[] Kseed = { 0x687a66d9, 0x0648f993, 0x867e121f,
+ 0x4ddf9ddb, 0x1205584 };
+ BigInteger k = dsa.generateK(Kseed, q512);
+ p.println("k: " + k.toString(16));
+ BigInteger r = dsa.generateR(p512, q512, g512, k);
+ p.println("r: " + r.toString(16));
+ byte[] abc = { 0x61, 0x62, 0x63 };
+ dsa.dataSHA.update(abc);
+ BigInteger s = dsa.generateS(x512, q512, r, k);
+ p.println("s: " + s.toString(16));
+
+ dsa.dataSHA.update(abc);
+ BigInteger w = dsa.generateW(p512, q512, g512, s);
+ p.println("w: " + w.toString(16));
+ BigInteger v = dsa.generateV(y512, p512, q512, g512, w, r);
+ p.println("v: " + v.toString(16));
+ if (v.equals(r)) {
+ p.println("signature verifies.");
+ } else {
+ p.println("signature does not verify.");
+ }
+ }
+
+ /* Test vector: 512-bit keys generated by our key generator. */
+
+ static BigInteger p512 =
+ new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecb" +
+ "cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1" +
+ "2ed0899bcd132acd50d99151bdc43ee737592e17", 16);
+
+ static BigInteger q512 =
+ new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
+
+ static BigInteger g512 =
+ new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a43" +
+ "4d6486931d2d14271b9e35030b71fd73da179069b32e" +
+ "2935630e1c2062354d0da20a6c416e50be794ca4", 16);
+
+ static BigInteger x512 =
+ new BigInteger("3406c2d71b04b5fc0db62afcad58a6607d3de688", 16);
+
+ static BigInteger y512 =
+ new BigInteger("2d335d76b8ec9d610aa8f2cbb4b149fd96fdd" +
+ "3a9a6e62bd6c2e01d406be4d1d72718a2fe08bea6d12f5e452474461f70f4" +
+ "dea60508e9fe2eaec23d2ec5d1a866", 16);
+
+ /* Official NIST 512-bit test keys */
+
+ static String pString = "8df2a494492276aa3d25759bb06869cbeac0d83afb8d0" +
+ "cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec" +
+ "0736ee31c80291";
+
+ static BigInteger testP = new BigInteger(pString, 16);
+
+ static String gString = "626d027839ea0a13413163a55b4cb500299d5522956ce" +
+ "fcb3bff10f399ce2c2e71cb9de5fa24babf58e5b79521925c9cc42e9f6f464b088cc5" +
+ "72af53e6d78802";
+
+ static BigInteger testG = new BigInteger(gString, 16);
+
+ static BigInteger testQ = new BigInteger("c773218c737ec8ee993b4f2ded30" +
+ "f48edace915f", 16);
+
+ static BigInteger testX = new BigInteger("2070b3223dba372fde1c0ffc7b2e" +
+ "3b498b260614", 16);
+
+ static String yString = "19131871d75b1612a819f29d78d1b0d7346f7aa77" +
+ "bb62a859bfd6c5675da9d212d3a36ef1672ef660b8c7c255cc0ec74858fba33f44c06" +
+ "699630a76b030ee333";
+
+ static BigInteger testY = new BigInteger(yString, 16);
+
+ /* End test vector values */
+
+ private static void debug(String s) {
+ if (debug) {
+ System.err.println(s);
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/provider/DSAKeyFactory.java b/base/util/src/netscape/security/provider/DSAKeyFactory.java
new file mode 100755
index 000000000..41f0081f2
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAKeyFactory.java
@@ -0,0 +1,232 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * This class implements the DSA key factory of the Sun provider.
+ *
+ * @author Jan Luehe
+ *
+ * @version 1.8, 97/12/10
+ *
+ * @since JDK1.2
+ */
+
+public class DSAKeyFactory extends KeyFactorySpi {
+
+ /**
+ * Generates a public key object from the provided key specification
+ * (key material).
+ *
+ * @param keySpec the specification (key material) of the public key
+ *
+ * @return the public key
+ *
+ * @exception InvalidKeySpecException if the given key specification
+ * is inappropriate for this key factory to produce a public key.
+ */
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ try {
+ if (keySpec instanceof DSAPublicKeySpec) {
+ DSAPublicKeySpec dsaPubKeySpec = (DSAPublicKeySpec) keySpec;
+ return new DSAPublicKey(dsaPubKeySpec.getY(),
+ dsaPubKeySpec.getP(),
+ dsaPubKeySpec.getQ(),
+ dsaPubKeySpec.getG());
+
+ } else if (keySpec instanceof X509EncodedKeySpec) {
+ return new DSAPublicKey(((X509EncodedKeySpec) keySpec).getEncoded());
+
+ } else {
+ throw new InvalidKeySpecException("Inappropriate key specification");
+ }
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException("Inappropriate key specification: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Generates a private key object from the provided key specification
+ * (key material).
+ *
+ * @param keySpec the specification (key material) of the private key
+ *
+ * @return the private key
+ *
+ * @exception InvalidKeySpecException if the given key specification
+ * is inappropriate for this key factory to produce a private key.
+ */
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ try {
+ if (keySpec instanceof DSAPrivateKeySpec) {
+ DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec) keySpec;
+ return new DSAPrivateKey(dsaPrivKeySpec.getX(),
+ dsaPrivKeySpec.getP(),
+ dsaPrivKeySpec.getQ(),
+ dsaPrivKeySpec.getG());
+
+ } else if (keySpec instanceof PKCS8EncodedKeySpec) {
+ return new DSAPrivateKey(((PKCS8EncodedKeySpec) keySpec).getEncoded());
+
+ } else {
+ throw new InvalidKeySpecException("Inappropriate key specification");
+ }
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException("Inappropriate key specification: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a specification (key material) of the given key object
+ * in the requested format.
+ *
+ * @param key the key
+ *
+ * @param keySpec the requested format in which the key material shall be
+ * returned
+ *
+ * @return the underlying key specification (key material) in the
+ * requested format
+ *
+ * @exception InvalidKeySpecException if the requested key specification is
+ * inappropriate for the given key, or the given key cannot be processed
+ * (e.g., the given key has an unrecognized algorithm or format).
+ */
+ @SuppressWarnings("unchecked")
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+
+ DSAParams params;
+
+ try {
+
+ if (key instanceof java.security.interfaces.DSAPublicKey) {
+
+ // Determine valid key specs
+ Class<?> dsaPubKeySpec = Class.forName
+ ("java.security.spec.DSAPublicKeySpec");
+ Class<?> x509KeySpec = Class.forName
+ ("java.security.spec.X509EncodedKeySpec");
+
+ if (dsaPubKeySpec.isAssignableFrom(keySpec)) {
+ java.security.interfaces.DSAPublicKey dsaPubKey = (java.security.interfaces.DSAPublicKey) key;
+ params = dsaPubKey.getParams();
+ return (T) new DSAPublicKeySpec(dsaPubKey.getY(),
+ params.getP(),
+ params.getQ(),
+ params.getG());
+
+ } else if (x509KeySpec.isAssignableFrom(keySpec)) {
+ return (T) new X509EncodedKeySpec(key.getEncoded());
+
+ } else {
+ throw new InvalidKeySpecException("Inappropriate key specification");
+ }
+
+ } else if (key instanceof java.security.interfaces.DSAPrivateKey) {
+
+ // Determine valid key specs
+ Class<?> dsaPrivKeySpec = Class.forName
+ ("java.security.spec.DSAPrivateKeySpec");
+ Class<?> pkcs8KeySpec = Class.forName
+ ("java.security.spec.PKCS8EncodedKeySpec");
+
+ if (dsaPrivKeySpec.isAssignableFrom(keySpec)) {
+ java.security.interfaces.DSAPrivateKey dsaPrivKey = (java.security.interfaces.DSAPrivateKey) key;
+ params = dsaPrivKey.getParams();
+ return (T) new DSAPrivateKeySpec(dsaPrivKey.getX(),
+ params.getP(),
+ params.getQ(),
+ params.getG());
+
+ } else if (pkcs8KeySpec.isAssignableFrom(keySpec)) {
+ return (T) new PKCS8EncodedKeySpec(key.getEncoded());
+
+ } else {
+ throw new InvalidKeySpecException("Inappropriate key specification");
+ }
+
+ } else {
+ throw new InvalidKeySpecException("Inappropriate key type");
+ }
+
+ } catch (ClassNotFoundException e) {
+ throw new InvalidKeySpecException("Unsupported key specification: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Translates a key object, whose provider may be unknown or potentially
+ * untrusted, into a corresponding key object of this key factory.
+ *
+ * @param key the key whose provider is unknown or untrusted
+ *
+ * @return the translated key
+ *
+ * @exception InvalidKeyException if the given key cannot be processed by
+ * this key factory.
+ */
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+
+ try {
+
+ if (key instanceof java.security.interfaces.DSAPublicKey) {
+ // Check if key originates from this factory
+ if (key instanceof netscape.security.provider.DSAPublicKey) {
+ return key;
+ }
+ // Convert key to spec
+ DSAPublicKeySpec dsaPubKeySpec = engineGetKeySpec(key, DSAPublicKeySpec.class);
+ // Create key from spec, and return it
+ return engineGeneratePublic(dsaPubKeySpec);
+
+ } else if (key instanceof java.security.interfaces.DSAPrivateKey) {
+ // Check if key originates from this factory
+ if (key instanceof netscape.security.provider.DSAPrivateKey) {
+ return key;
+ }
+ // Convert key to spec
+ DSAPrivateKeySpec dsaPrivKeySpec = engineGetKeySpec(key, DSAPrivateKeySpec.class);
+ // Create key from spec, and return it
+ return engineGeneratePrivate(dsaPrivKeySpec);
+
+ } else {
+ throw new InvalidKeyException("Wrong algorithm type");
+ }
+
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException("Cannot translate key: "
+ + e.getMessage());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSAKeyPairGenerator.java b/base/util/src/netscape/security/provider/DSAKeyPairGenerator.java
new file mode 100644
index 000000000..3e04792bf
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAKeyPairGenerator.java
@@ -0,0 +1,398 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGenerator;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.ProviderException;
+import java.security.SecureRandom;
+import java.security.interfaces.DSAParams;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Hashtable;
+
+import netscape.security.x509.AlgIdDSA;
+
+/**
+ * This class generates DSA key parameters and public/private key
+ * pairs according to the DSS standard NIST FIPS 186. It uses the
+ * updated version of SHA, SHA-1 as described in FIPS 180-1.
+ *
+ * @author Benjamin Renaud
+ *
+ * @version 1.23, 97/12/10
+ */
+
+public class DSAKeyPairGenerator extends KeyPairGenerator
+ implements java.security.interfaces.DSAKeyPairGenerator {
+
+ private static Hashtable<Integer, AlgIdDSA> precomputedParams;
+
+ static {
+
+ /* We support precomputed parameter for 512, 768 and 1024 bit
+ moduli. In this file we provide both the seed and counter
+ value of the generation process for each of these seeds,
+ for validation purposes. We also include the test vectors
+ from the DSA specification, FIPS 186, and the FIPS 186
+ Change No 1, which updates the test vector using SHA-1
+ instead of SHA (for both the G function and the message
+ hash.
+ */
+
+ precomputedParams = new Hashtable<Integer, AlgIdDSA>();
+
+ /*
+ * L = 512
+ * SEED = b869c82b35d70e1b1ff91b28e37a62ecdc34409b
+ * counter = 123
+ */
+ BigInteger p512 =
+ new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecb" +
+ "cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1" +
+ "2ed0899bcd132acd50d99151bdc43ee737592e17", 16);
+
+ BigInteger q512 =
+ new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
+
+ BigInteger g512 =
+ new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a43" +
+ "4d6486931d2d14271b9e35030b71fd73da179069b32e" +
+ "2935630e1c2062354d0da20a6c416e50be794ca4", 16);
+
+ /*
+ * L = 768
+ * SEED = 77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399
+ * counter = 263
+ */
+ BigInteger p768 =
+ new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e" +
+ "927b3a9670fbec5d890141922d2c3b3ad24800937" +
+ "99869d1e846aab49fab0ad26d2ce6a22219d470bc" +
+ "e7d777d4a21fbe9c270b57f607002f3cef8393694" +
+ "cf45ee3688c11a8c56ab127a3daf", 16);
+
+ BigInteger q768 =
+ new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511",
+ 16);
+
+ BigInteger g768 =
+ new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5fac" +
+ "baecbe95f190aa7a31d23c4dbbcbe06174544401a" +
+ "5b2c020965d8c2bd2171d3668445771f74ba084d2" +
+ "029d83c1c158547f3a9f1a2715be23d51ae4d3e5a" +
+ "1f6a7064f316933a346d3f529252", 16);
+
+ /*
+ * L = 1024
+ * SEED = 8d5155894229d5e689ee01e6018a237e2cae64cd
+ * counter = 92
+ */
+ BigInteger p1024 =
+ new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523c" +
+ "ef4400c31e3f80b6512669455d402251fb593d8d58" +
+ "fabfc5f5ba30f6cb9b556cd7813b801d346ff26660" +
+ "b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" +
+ "1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554" +
+ "135a169132f675f3ae2b61d72aeff22203199dd148" +
+ "01c7", 16);
+
+ BigInteger q1024 =
+ new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5",
+ 16);
+
+ BigInteger g1024 =
+ new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa" +
+ "3aea82f9574c0b3d0782675159578ebad4594fe671" +
+ "07108180b449167123e84c281613b7cf09328cc8a6" +
+ "e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" +
+ "0bfa213562f1fb627a01243bcca4f1bea8519089a8" +
+ "83dfe15ae59f06928b665e807b552564014c3bfecf" +
+ "492a", 16);
+
+ try {
+ AlgIdDSA alg512 = new AlgIdDSA(p512, q512, g512);
+ AlgIdDSA alg768 = new AlgIdDSA(p768, q768, g768);
+ AlgIdDSA alg1024 = new AlgIdDSA(p1024, q1024, g1024);
+
+ precomputedParams.put(Integer.valueOf(512), alg512);
+ precomputedParams.put(Integer.valueOf(768), alg768);
+ precomputedParams.put(Integer.valueOf(1024), alg1024);
+
+ } catch (Exception e) {
+ throw new InternalError("initializing precomputed " +
+ "algorithm parameters for Sun DSA");
+ }
+ }
+
+ /* The modulus length */
+ private int modlen = 1024;
+
+ /* Generate new parameters, even if we have precomputed ones. */
+ boolean generateNewParameters = false;
+
+ /* preset algorithm parameters. */
+ private BigInteger presetP, presetQ, presetG;
+
+ /* The source of random bits to use */
+ SecureRandom random;
+
+ public DSAKeyPairGenerator() {
+ super("DSA");
+ }
+
+ public void initialize(int strength, SecureRandom random) {
+ if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) {
+ throw new InvalidParameterException("Modulus size must range from 512 to 1024 "
+ + "and be a multiple of 64");
+ }
+
+ /* Set the random */
+ this.random = random;
+ if (this.random == null) {
+ this.random = new SecureRandom();
+ }
+
+ this.modlen = strength;
+ DSAParams params = null;
+
+ /* Find the precomputed parameters, if any */
+ if (!generateNewParameters) {
+ Integer mod = Integer.valueOf(this.modlen);
+ params = precomputedParams.get(mod);
+ }
+ if (params != null) {
+ setParams(params);
+ }
+ }
+
+ /**
+ * Initializes the DSA key pair generator. If <code>genParams</code> is false, a set of pre-computed parameters is
+ * used. In this case, <code>modelen</code> must be 512, 768, or 1024.
+ */
+ public void initialize(int modlen, boolean genParams, SecureRandom random)
+ throws InvalidParameterException {
+ if (genParams == false && modlen != 512 && modlen != 768
+ && modlen != 1024) {
+ throw new InvalidParameterException("No precomputed parameters for requested modulus size "
+ + "available");
+ }
+ this.generateNewParameters = genParams;
+ initialize(modlen, random);
+ }
+
+ /**
+ * Initializes the DSA object using a DSA parameter object.
+ *
+ * @param params a fully initialized DSA parameter object.
+ */
+ public void initialize(DSAParams params, SecureRandom random)
+ throws InvalidParameterException {
+ initialize(params.getP().bitLength(), random);
+ setParams(params);
+ }
+
+ /**
+ * Initializes the DSA object using a parameter object.
+ *
+ * @param params the parameter set to be used to generate
+ * the keys.
+ * @param random the source of randomness for this generator.
+ *
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * are inappropriate for this key pair generator
+ */
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (!(params instanceof DSAParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("Inappropriate parameter");
+ }
+ initialize(((DSAParameterSpec) params).getP().bitLength(),
+ random);
+ setParams((DSAParameterSpec) params);
+ }
+
+ /**
+ * Generates a pair of keys usable by any JavaSecurity compliant
+ * DSA implementation.
+ *
+ * @param rnd the source of random bits from which the random key
+ * generation parameters are drawn. In particular, this includes
+ * the XSEED parameter.
+ *
+ * @exception InvalidParameterException if the modulus is not
+ * between 512 and 1024.
+ */
+ public KeyPair generateKeyPair() {
+
+ // set random if initialize() method has been skipped
+ if (this.random == null) {
+ this.random = new SecureRandom();
+ }
+
+ if (presetP == null || presetQ == null || presetG == null ||
+ generateNewParameters) {
+
+ AlgorithmParameterGenerator dsaParamGen;
+
+ try {
+ dsaParamGen = AlgorithmParameterGenerator.getInstance("DSA",
+ "SUN");
+ } catch (NoSuchAlgorithmException e) {
+ // this should never happen, because we provide it
+ throw new RuntimeException(e.getMessage());
+ } catch (NoSuchProviderException e) {
+ // this should never happen, because we provide it
+ throw new RuntimeException(e.getMessage());
+ }
+
+ dsaParamGen.init(modlen, random);
+
+ DSAParameterSpec dsaParamSpec;
+ try {
+ dsaParamSpec = (DSAParameterSpec)
+ dsaParamGen.generateParameters().getParameterSpec
+ (DSAParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ // this should never happen
+ throw new RuntimeException(e.getMessage());
+ }
+ presetP = dsaParamSpec.getP();
+ presetQ = dsaParamSpec.getQ();
+ presetG = dsaParamSpec.getG();
+ }
+
+ return generateKeyPair(presetP, presetQ, presetG, random);
+ }
+
+ public KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g,
+ SecureRandom random) {
+
+ BigInteger x = generateX(random, q);
+ BigInteger y = generateY(x, p, g);
+
+ try {
+ DSAPublicKey pub = new DSAPublicKey(y, p, q, g);
+ DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g);
+
+ KeyPair pair = new KeyPair(pub, priv);
+ return pair;
+
+ } catch (InvalidKeyException e) {
+ throw new ProviderException(e.getMessage());
+ }
+ }
+
+ /* Test vectors from the DSA specs. */
+
+ private static int[] testXSeed = { 0xbd029bbe, 0x7f51960b, 0xcf9edb2b,
+ 0x61f06f0f, 0xeb5a38b6 };
+
+ private int[] x_t = { 0x67452301, 0xefcdab89, 0x98badcfe,
+ 0x10325476, 0xc3d2e1f0 };
+
+ /**
+ * Generate the private key component of the key pair using the
+ * provided source of random bits. This method uses the random but
+ * source passed to generate a seed and then calls the seed-based
+ * generateX method.
+ */
+ private BigInteger generateX(SecureRandom random, BigInteger q) {
+ BigInteger x = null;
+ while (true) {
+ int[] seed = new int[5];
+ for (int i = 0; i < 5; i++) {
+ seed[i] = random.nextInt();
+ }
+ x = generateX(seed, q);
+ if (x.signum() > 0 && (x.compareTo(q) < 0)) {
+ break;
+ }
+ }
+ return x;
+ }
+
+ /**
+ * Given a seed, generate the private key component of the key
+ * pair. In the terminology used in the DSA specification
+ * (FIPS-186) seed is the XSEED quantity.
+ *
+ * @param seed the seed to use to generate the private key.
+ */
+ BigInteger generateX(int[] seed, BigInteger q) {
+
+ /* Test vector
+ int[] tseed = { 0xbd029bbe, 0x7f51960b, 0xcf9edb2b,
+ 0x61f06f0f, 0xeb5a38b6 };
+ seed = tseed;
+ */
+ // check out t in the spec.
+ int[] t = { 0x67452301, 0xEFCDAB89, 0x98BADCFE,
+ 0x10325476, 0xC3D2E1F0 };
+ //
+
+ int[] tmp = DSA.SHA_7(seed, t);
+ byte[] tmpBytes = new byte[tmp.length * 4];
+ for (int i = 0; i < tmp.length; i++) {
+ int k = tmp[i];
+ for (int j = 0; j < 4; j++) {
+ tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8)));
+ }
+ }
+ BigInteger x = new BigInteger(1, tmpBytes).mod(q);
+ return x;
+ }
+
+ /**
+ * Generate the public key component y of the key pair.
+ *
+ * @param x the private key component.
+ *
+ * @param p the base parameter.
+ */
+ BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) {
+ BigInteger y = g.modPow(x, p);
+ return y;
+ }
+
+ /**
+ * Set the parameters.
+ */
+ private void setParams(DSAParams params) {
+ presetP = params.getP();
+ presetQ = params.getQ();
+ presetG = params.getG();
+ }
+
+ /**
+ * Set the parameters.
+ */
+ private void setParams(DSAParameterSpec params) {
+ presetP = params.getP();
+ presetQ = params.getQ();
+ presetG = params.getG();
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSAParameterGenerator.java b/base/util/src/netscape/security/provider/DSAParameterGenerator.java
new file mode 100755
index 000000000..cd7b8de33
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAParameterGenerator.java
@@ -0,0 +1,299 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/*
+ * This class generates parameters for the DSA algorithm. It uses a default
+ * prime modulus size of 1024 bits, which can be overwritten during
+ * initialization.
+ *
+ * @author Jan Luehe
+ *
+ * @version 1.4, 97/12/10
+ *
+ * @see java.security.AlgorithmParameters
+ * @see java.security.spec.AlgorithmParameterSpec
+ * @see DSAParameters
+ *
+ * @since JDK1.2
+ */
+
+public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
+
+ // the modulus length
+ private int modLen = 1024; // default
+
+ // the source of randomness
+ private SecureRandom random;
+
+ // useful constants
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ // Make a SHA-1 hash function
+ private SHA sha;
+
+ public DSAParameterGenerator() {
+ this.sha = new SHA();
+ }
+
+ /**
+ * Initializes this parameter generator for a certain strength
+ * and source of randomness.
+ *
+ * @param strength the strength (size of prime) in bits
+ * @param random the source of randomness
+ */
+ protected void engineInit(int strength, SecureRandom random) {
+ /*
+ * Bruce Schneier, "Applied Cryptography", 2nd Edition,
+ * Description of DSA:
+ * [...] The algorithm uses the following parameter:
+ * p=a prime number L bits long, when L ranges from 512 to 1024 and is
+ * a multiple of 64. [...]
+ */
+ if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) {
+ throw new InvalidParameterException("Prime size must range from 512 to 1024 "
+ + "and be a multiple of 64");
+ }
+ this.modLen = strength;
+ this.random = random;
+ }
+
+ /**
+ * Initializes this parameter generator with a set of
+ * algorithm-specific parameter generation values.
+ *
+ * @param params the set of algorithm-specific parameter generation values
+ * @param random the source of randomness
+ *
+ * @exception InvalidAlgorithmParameterException if the given parameter
+ * generation values are inappropriate for this parameter generator
+ */
+ protected void engineInit(AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ throw new InvalidAlgorithmParameterException("Invalid parameter");
+ }
+
+ /**
+ * Generates the parameters.
+ *
+ * @return the new AlgorithmParameters object
+ */
+ protected AlgorithmParameters engineGenerateParameters() {
+ AlgorithmParameters algParams = null;
+ try {
+ if (this.random == null) {
+ this.random = new SecureRandom();
+ }
+
+ BigInteger[] pAndQ = generatePandQ(this.random, this.modLen);
+ BigInteger paramP = pAndQ[0];
+ BigInteger paramQ = pAndQ[1];
+ BigInteger paramG = generateG(paramP, paramQ);
+
+ DSAParameterSpec dsaParamSpec = new DSAParameterSpec(paramP,
+ paramQ,
+ paramG);
+ algParams = AlgorithmParameters.getInstance("DSA", "SUN");
+ algParams.init(dsaParamSpec);
+ } catch (InvalidParameterSpecException e) {
+ // this should never happen
+ throw new RuntimeException(e.getMessage());
+ } catch (NoSuchAlgorithmException e) {
+ // this should never happen, because we provide it
+ throw new RuntimeException(e.getMessage());
+ } catch (NoSuchProviderException e) {
+ // this should never happen, because we provide it
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return algParams;
+ }
+
+ /*
+ * Generates the prime and subprime parameters for DSA,
+ * using the provided source of randomness.
+ * This method will generate new seeds until a suitable
+ * seed has been found.
+ *
+ * @param random the source of randomness to generate the
+ * seed
+ * @param L the size of <code>p</code>, in bits.
+ *
+ * @return an array of BigInteger, with <code>p</code> at index 0 and
+ * <code>q</code> at index 1.
+ */
+ BigInteger[] generatePandQ(SecureRandom random, int L) {
+ BigInteger[] result = null;
+ byte[] seed = new byte[20];
+
+ while (result == null) {
+ for (int i = 0; i < 20; i++) {
+ seed[i] = (byte) random.nextInt();
+ }
+ result = generatePandQ(seed, L);
+ }
+ return result;
+ }
+
+ /*
+ * Generates the prime and subprime parameters for DSA.
+ *
+ * <p>The seed parameter corresponds to the <code>SEED</code> parameter
+ * referenced in the FIPS specification of the DSA algorithm,
+ * and L is the size of <code>p</code>, in bits.
+ *
+ * @param seed the seed to generate the parameters
+ * @param L the size of <code>p</code>, in bits.
+ *
+ * @return an array of BigInteger, with <code>p</code> at index 0,
+ * <code>q</code> at index 1, the seed at index 2, and the counter value
+ * at index 3, or null if the seed does not yield suitable numbers.
+ */
+ BigInteger[] generatePandQ(byte[] seed, int L) {
+
+ /* Useful variables */
+ int g = seed.length * 8;
+ int n = (L - 1) / 160;
+ int b = (L - 1) % 160;
+
+ BigInteger SEED = new BigInteger(1, seed);
+ BigInteger TWOG = TWO.pow(2 * g);
+
+ /* Step 2 (Step 1 is getting seed). */
+ byte[] U1 = SHA(seed);
+ byte[] U2 = SHA(toByteArray((SEED.add(ONE)).mod(TWOG)));
+
+ xor(U1, U2);
+ byte[] U = U1;
+
+ /* Step 3: For q by setting the msb and lsb to 1 */
+ U[0] |= 0x80;
+ U[19] |= 1;
+ BigInteger q = new BigInteger(1, U);
+
+ /* Step 5 */
+ if (!q.isProbablePrime(40)) {
+ return null;
+
+ } else {
+ BigInteger V[] = new BigInteger[n + 1];
+ BigInteger offset = TWO;
+
+ /* Step 6 */
+ for (int counter = 0; counter < 4096; counter++) {
+
+ /* Step 7 */
+ for (int k = 0; k <= n; k++) {
+ BigInteger K = BigInteger.valueOf(k);
+ BigInteger tmp = (SEED.add(offset).add(K)).mod(TWOG);
+ V[k] = new BigInteger(1, SHA(toByteArray(tmp)));
+ }
+
+ /* Step 8 */
+ BigInteger W = V[0];
+ for (int i = 1; i < n; i++) {
+ W = W.add(V[i].multiply(TWO.pow(i * 160)));
+ }
+ W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * 160)));
+
+ BigInteger TWOLm1 = TWO.pow(L - 1);
+ BigInteger X = W.add(TWOLm1);
+
+ /* Step 9 */
+ BigInteger c = X.mod(q.multiply(TWO));
+ BigInteger p = X.subtract(c.subtract(ONE));
+
+ /* Step 10 - 13 */
+ if (p.compareTo(TWOLm1) > -1 && p.isProbablePrime(15)) {
+ BigInteger[] result = { p, q, SEED,
+ BigInteger.valueOf(counter) };
+ return result;
+ }
+ offset = offset.add(BigInteger.valueOf(n)).add(ONE);
+ }
+ return null;
+ }
+ }
+
+ /*
+ * Generates the <code>g</code> parameter for DSA.
+ *
+ * @param p the prime, <code>p</code>.
+ * @param q the subprime, <code>q</code>.
+ *
+ * @param the <code>g</code>
+ */
+ BigInteger generateG(BigInteger p, BigInteger q) {
+ BigInteger h = ONE;
+ BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q);
+ BigInteger g = ONE;
+ while (g.compareTo(TWO) < 0) {
+ g = h.modPow(pMinusOneOverQ, p);
+ h = h.add(ONE);
+ }
+ return g;
+ }
+
+ /*
+ * Returns the SHA-1 digest of some data
+ */
+ private byte[] SHA(byte[] array) {
+ sha.engineReset();
+ sha.engineUpdate(array, 0, array.length);
+ return sha.engineDigest();
+ }
+
+ /*
+ * Converts the result of a BigInteger.toByteArray call to an exact
+ * signed magnitude representation for any positive number.
+ */
+ private byte[] toByteArray(BigInteger bigInt) {
+ byte[] result = bigInt.toByteArray();
+ if (result[0] == 0) {
+ byte[] tmp = new byte[result.length - 1];
+ System.arraycopy(result, 1, tmp, 0, tmp.length);
+ result = tmp;
+ }
+ return result;
+ }
+
+ /*
+ * XORs U2 into U1
+ */
+ private void xor(byte[] U1, byte[] U2) {
+ for (int i = 0; i < U1.length; i++) {
+ U1[i] ^= U2[i];
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSAParameters.java b/base/util/src/netscape/security/provider/DSAParameters.java
new file mode 100755
index 000000000..e2a5dd128
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAParameters.java
@@ -0,0 +1,130 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the parameter set used by the
+ * Digital Signature Algorithm as specified in the FIPS 186
+ * standard.
+ *
+ * @author Jan Luehe
+ *
+ * @version 1.8, 97/12/10
+ *
+ * @since JDK1.2
+ */
+
+public class DSAParameters extends AlgorithmParametersSpi {
+
+ // the prime (p)
+ protected BigInteger p;
+
+ // the sub-prime (q)
+ protected BigInteger q;
+
+ // the base (g)
+ protected BigInteger g;
+
+ protected void engineInit(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException {
+ if (!(paramSpec instanceof DSAParameterSpec)) {
+ throw new InvalidParameterSpecException("Inappropriate parameter specification");
+ }
+ this.p = ((DSAParameterSpec) paramSpec).getP();
+ this.q = ((DSAParameterSpec) paramSpec).getQ();
+ this.g = ((DSAParameterSpec) paramSpec).getG();
+ }
+
+ protected void engineInit(byte[] params) throws IOException {
+ DerValue encodedParams = new DerValue(params);
+
+ if (encodedParams.tag != DerValue.tag_Sequence) {
+ throw new IOException("DSA params parsing error");
+ }
+
+ encodedParams.data.reset();
+
+ this.p = encodedParams.data.getInteger().toBigInteger();
+ this.q = encodedParams.data.getInteger().toBigInteger();
+ this.g = encodedParams.data.getInteger().toBigInteger();
+
+ if (encodedParams.data.available() != 0) {
+ throw new IOException("encoded params have " +
+ encodedParams.data.available() +
+ " extra bytes");
+ }
+ }
+
+ protected void engineInit(byte[] params, String decodingMethod)
+ throws IOException {
+ engineInit(params);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> paramSpec)
+ throws InvalidParameterSpecException {
+ try {
+ Class<?> dsaParamSpec = Class.forName
+ ("java.security.spec.DSAParameterSpec");
+ if (dsaParamSpec.isAssignableFrom(paramSpec)) {
+ return (T) new DSAParameterSpec(this.p, this.q, this.g);
+ } else {
+ throw new InvalidParameterSpecException("Inappropriate parameter Specification");
+ }
+ } catch (ClassNotFoundException e) {
+ throw new InvalidParameterSpecException("Unsupported parameter specification: " + e.getMessage());
+ }
+ }
+
+ protected byte[] engineGetEncoded() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream bytes = new DerOutputStream();
+
+ bytes.putInteger(new BigInt(p.toByteArray()));
+ bytes.putInteger(new BigInt(q.toByteArray()));
+ bytes.putInteger(new BigInt(g.toByteArray()));
+ out.write(DerValue.tag_Sequence, bytes);
+ return out.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(String encodingMethod)
+ throws IOException {
+ return engineGetEncoded();
+ }
+
+ /*
+ * Returns a formatted string describing the parameters.
+ */
+ protected String engineToString() {
+ return "\n\tp: " + new BigInt(p).toString()
+ + "\n\tq: " + new BigInt(q).toString()
+ + "\n\tg: " + new BigInt(g).toString()
+ + "\n";
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSAPrivateKey.java b/base/util/src/netscape/security/provider/DSAPrivateKey.java
new file mode 100644
index 000000000..0cfc5e5ea
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAPrivateKey.java
@@ -0,0 +1,147 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.interfaces.DSAParams;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import netscape.security.pkcs.PKCS8Key;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.AlgIdDSA;
+
+/**
+ * A PKCS#8 private key for the Digital Signature Algorithm.
+ *
+ * @author Benjamin Renaud
+ *
+ * @version 1.47, 97/12/10
+ *
+ * @see DSAPublicKey
+ * @see AlgIdDSA
+ * @see DSA
+ */
+
+public final class DSAPrivateKey extends PKCS8Key
+ implements java.security.interfaces.DSAPrivateKey, Serializable {
+
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = -3244453684193605938L;
+
+ /* the private key */
+ private BigInteger x;
+
+ /*
+ * Keep this constructor for backwards compatibility with JDK1.1.
+ */
+ public DSAPrivateKey() {
+ }
+
+ /**
+ * Make a DSA private key out of a private key and three parameters.
+ */
+ public DSAPrivateKey(BigInteger x, BigInteger p,
+ BigInteger q, BigInteger g)
+ throws InvalidKeyException {
+ this.x = x;
+ algid = new AlgIdDSA(p, q, g);
+
+ try {
+ key = new DerValue(DerValue.tag_Integer,
+ x.toByteArray()).toByteArray();
+ encode();
+ } catch (IOException e) {
+ throw new InvalidKeyException("could not DER encode x: " +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Make a DSA private key from its DER encoding (PKCS #8).
+ */
+ public DSAPrivateKey(byte[] encoded) throws InvalidKeyException {
+ clearOldKey();
+ decode(encoded);
+ }
+
+ /**
+ * Returns the DSA parameters associated with this key, or null if the
+ * parameters could not be parsed.
+ */
+ public DSAParams getParams() {
+ try {
+ if (algid instanceof DSAParams) {
+ return (DSAParams) algid;
+ } else {
+ DSAParameterSpec paramSpec;
+ AlgorithmParameters algParams = algid.getParameters();
+ if (algParams == null) {
+ return null;
+ }
+ paramSpec = (DSAParameterSpec) algParams.getParameterSpec
+ (DSAParameterSpec.class);
+ return (DSAParams) paramSpec;
+ }
+ } catch (InvalidParameterSpecException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get the raw private key, x, without the parameters.
+ *
+ */
+ public BigInteger getX() {
+ return x;
+ }
+
+ private void clearOldKey() {
+ int i;
+ if (this.encodedKey != null) {
+ for (i = 0; i < this.encodedKey.length; i++) {
+ this.encodedKey[i] = (byte) 0x00;
+ }
+ }
+ if (this.key != null) {
+ for (i = 0; i < this.key.length; i++) {
+ this.key[i] = (byte) 0x00;
+ }
+ }
+ }
+
+ public String toString() {
+ return "Sun DSA Private Key \nparameters:" + algid + "\nx: " +
+ x.toString(16) + "\n";
+ }
+
+ protected void parseKeyBits() throws InvalidKeyException {
+ DerInputStream in = new DerInputStream(key);
+
+ try {
+ x = in.getInteger().toBigInteger();
+ } catch (IOException e) {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/provider/DSAPublicKey.java b/base/util/src/netscape/security/provider/DSAPublicKey.java
new file mode 100644
index 000000000..89262809b
--- /dev/null
+++ b/base/util/src/netscape/security/provider/DSAPublicKey.java
@@ -0,0 +1,133 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.interfaces.DSAParams;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.AlgIdDSA;
+import netscape.security.x509.X509Key;
+
+/**
+ * An X.509 public key for the Digital Signature Algorithm.
+ *
+ * @author Benjamin Renaud
+ *
+ * @version 1.52, 97/12/10
+ *
+ * @see DSAPrivateKey
+ * @see AlgIdDSA
+ * @see DSA
+ */
+
+public final class DSAPublicKey extends X509Key
+ implements java.security.interfaces.DSAPublicKey, Serializable {
+
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = -2994193307391104133L;
+
+ /* the public key */
+ private BigInteger y;
+
+ /*
+ * Keep this constructor for backwards compatibility with JDK1.1.
+ */
+ public DSAPublicKey() {
+ }
+
+ /**
+ * Make a DSA public key out of a public key and three parameters.
+ */
+ public DSAPublicKey(BigInteger y, BigInteger p, BigInteger q,
+ BigInteger g)
+ throws InvalidKeyException {
+ this.y = y;
+ algid = new AlgIdDSA(p, q, g);
+
+ try {
+ key = new DerValue(DerValue.tag_Integer,
+ y.toByteArray()).toByteArray();
+ encode();
+ } catch (IOException e) {
+ throw new InvalidKeyException("could not DER encode y: " +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Make a DSA public key from its DER encoding (X.509).
+ */
+ public DSAPublicKey(byte[] encoded) throws InvalidKeyException {
+ decode(encoded);
+ }
+
+ /**
+ * Returns the DSA parameters associated with this key, or null if the
+ * parameters could not be parsed.
+ */
+ public DSAParams getParams() {
+ try {
+ if (algid instanceof DSAParams) {
+ return (DSAParams) algid;
+ } else {
+ DSAParameterSpec paramSpec;
+ AlgorithmParameters algParams = algid.getParameters();
+ if (algParams == null) {
+ return null;
+ }
+ paramSpec = (DSAParameterSpec) algParams.getParameterSpec
+ (DSAParameterSpec.class);
+ return (DSAParams) paramSpec;
+ }
+ } catch (InvalidParameterSpecException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get the raw public value, y, without the parameters.
+ *
+ */
+ public BigInteger getY() {
+ return y;
+ }
+
+ public String toString() {
+ return "Sun DSA Public Key\n Parameters:" + algid
+ + "\n y:\n" + (new BigInt(y)).toString() + "\n";
+ }
+
+ protected void parseKeyBits() throws InvalidKeyException {
+ try {
+ DerInputStream in = new DerInputStream(key);
+ y = in.getInteger().toBigInteger();
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid key: y value\n" +
+ e.getMessage());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/provider/MD5.java b/base/util/src/netscape/security/provider/MD5.java
new file mode 100644
index 000000000..d7aeacaee
--- /dev/null
+++ b/base/util/src/netscape/security/provider/MD5.java
@@ -0,0 +1,378 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.DigestException;
+import java.security.MessageDigestSpi;
+
+/**
+ * The MD5 class is used to compute an MD5 message digest over a given
+ * buffer of bytes. It is an implementation of the RSA Data Security Inc
+ * MD5 algorithim as described in internet RFC 1321.
+ *
+ * @version 1.24 97/12/10
+ * @author Chuck McManis
+ * @author Benjamin Renaud
+ */
+
+public final class MD5 extends MessageDigestSpi implements Cloneable {
+
+ /** contains the computed message digest */
+ private byte[] digestBits;
+
+ private String algorithm;
+
+ private int state[];
+ private long count; // bit count AND buffer[] index aid
+ private byte buffer[];
+ private int transformBuffer[];
+
+ private static final int S11 = 7;
+ private static final int S12 = 12;
+ private static final int S13 = 17;
+ private static final int S14 = 22;
+ private static final int S21 = 5;
+ private static final int S22 = 9;
+ private static final int S23 = 14;
+ private static final int S24 = 20;
+ private static final int S31 = 4;
+ private static final int S32 = 11;
+ private static final int S33 = 16;
+ private static final int S34 = 23;
+ private static final int S41 = 6;
+ private static final int S42 = 10;
+ private static final int S43 = 15;
+ private static final int S44 = 21;
+
+ private static final int MD5_LENGTH = 16;
+
+ /**
+ * Standard constructor, creates a new MD5 instance, allocates its
+ * buffers from the heap.
+ */
+ public MD5() {
+ init();
+ }
+
+ /* **********************************************************
+ * The MD5 Functions. These are copied verbatim from
+ * the RFC to insure accuracy. The results of this
+ * implementation were checked against the RSADSI version.
+ * **********************************************************
+ */
+
+ private int F(int x, int y, int z) {
+ return ((x & y) | ((~x) & z));
+ }
+
+ private int G(int x, int y, int z) {
+ return ((x & z) | (y & (~z)));
+ }
+
+ private int H(int x, int y, int z) {
+ return ((x ^ y) ^ z);
+ }
+
+ private int I(int x, int y, int z) {
+ return (y ^ (x | (~z)));
+ }
+
+ private int rotateLeft(int a, int n) {
+ return ((a << n) | (a >>> (32 - n)));
+ }
+
+ private int FF(int a, int b, int c, int d, int x, int s, int ac) {
+ a += F(b, c, d) + x + ac;
+ a = rotateLeft(a, s);
+ a += b;
+ return a;
+ }
+
+ private int GG(int a, int b, int c, int d, int x, int s, int ac) {
+ a += G(b, c, d) + x + ac;
+ a = rotateLeft(a, s);
+ a += b;
+ return a;
+ }
+
+ private int HH(int a, int b, int c, int d, int x, int s, int ac) {
+ a += H(b, c, d) + x + ac;
+ a = rotateLeft(a, s);
+ a += b;
+ return a;
+ }
+
+ private int II(int a, int b, int c, int d, int x, int s, int ac) {
+ a += I(b, c, d) + x + ac;
+ a = rotateLeft(a, s);
+ a += b;
+ return a;
+ }
+
+ /**
+ * This is where the functions come together as the generic MD5
+ * transformation operation, it is called by update() which is
+ * synchronized (to protect transformBuffer). It consumes sixteen
+ * bytes from the buffer, beginning at the specified offset.
+ */
+ void transform(byte buf[], int offset) {
+ int a, b, c, d;
+ int x[] = transformBuffer;
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ for (int i = 0; i < 16; i++) {
+ x[i] = (int) buf[i * 4 + offset] & 0xff;
+ for (int j = 1; j < 4; j++) {
+ x[i] += ((int) buf[i * 4 + j + offset] & 0xff) << (j * 8);
+ }
+ }
+
+ /* Round 1 */
+ a = FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ d = FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ c = FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ b = FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ a = FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ d = FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ c = FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ b = FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ a = FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ d = FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ c = FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ b = FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ a = FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ d = FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ c = FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ b = FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ a = GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ d = GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ c = GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ a = GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ d = GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ c = GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ a = GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ d = GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ c = GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ b = GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ a = GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ c = GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ a = HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ d = HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ c = HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ b = HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ a = HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ b = HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ a = HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ d = HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ c = HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ b = HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ a = HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ d = HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ b = HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ a = II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ d = II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ c = II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ b = II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ a = II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ d = II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ c = II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ b = II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ a = II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ c = II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ b = II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ a = II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ d = II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ c = II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ b = II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ }
+
+ /**
+ * Initialize the MD5 state information and reset the bit count
+ * to 0. Given this implementation you are constrained to counting
+ * 2^64 bits.
+ */
+ public void init() {
+ state = new int[4];
+ transformBuffer = new int[16];
+ buffer = new byte[64];
+ digestBits = new byte[16];
+ count = 0;
+ // Load magic initialization constants.
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+ for (int i = 0; i < digestBits.length; i++)
+ digestBits[i] = 0;
+ }
+
+ protected void engineReset() {
+ init();
+ }
+
+ /**
+ * Return the digest length in bytes
+ */
+ protected int engineGetDigestLength() {
+ return (MD5_LENGTH);
+ }
+
+ /**
+ * Update adds the passed byte to the digested data.
+ */
+ protected synchronized void engineUpdate(byte b) {
+ int index;
+
+ index = (int) ((count >>> 3) & 0x3f);
+ count += 8;
+ buffer[index] = b;
+ if (index >= 63) {
+ transform(buffer, 0);
+ }
+ }
+
+ /**
+ * Update adds the selected part of an array of bytes to the digest.
+ * This version is more efficient than the byte-at-a-time version;
+ * it avoids data copies and reduces per-byte call overhead.
+ */
+ protected synchronized void engineUpdate(byte input[], int offset,
+ int len) {
+ int i;
+
+ for (i = offset; len > 0;) {
+ int index = (int) ((count >>> 3) & 0x3f);
+
+ if (index == 0 && len > 64) {
+ count += (64 * 8);
+ transform(input, i);
+ len -= 64;
+ i += 64;
+ } else {
+ count += 8;
+ buffer[index] = input[i];
+ if (index >= 63)
+ transform(buffer, 0);
+ i++;
+ len--;
+ }
+ }
+ }
+
+ /**
+ * Perform the final computations, any buffered bytes are added
+ * to the digest, the count is added to the digest, and the resulting
+ * digest is stored. After calling final you will need to call
+ * init() again to do another digest.
+ */
+ private void finish() {
+ byte bits[] = new byte[8];
+ byte padding[];
+ int i, index, padLen;
+
+ for (i = 0; i < 8; i++) {
+ bits[i] = (byte) ((count >>> (i * 8)) & 0xff);
+ }
+
+ index = (int) (count >> 3) & 0x3f;
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ padding = new byte[padLen];
+ padding[0] = (byte) 0x80;
+ engineUpdate(padding, 0, padding.length);
+ engineUpdate(bits, 0, bits.length);
+
+ for (i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ digestBits[i * 4 + j] = (byte) ((state[i] >>> (j * 8)) & 0xff);
+ }
+ }
+ }
+
+ /**
+ */
+ protected byte[] engineDigest() {
+ finish();
+
+ byte[] result = new byte[MD5_LENGTH];
+ System.arraycopy(digestBits, 0, result, 0, MD5_LENGTH);
+
+ init();
+
+ return result;
+ }
+
+ /**
+ */
+ protected int engineDigest(byte[] buf, int offset, int len)
+ throws DigestException {
+ finish();
+
+ if (len < MD5_LENGTH)
+ throw new DigestException("partial digests not returned");
+ if (buf.length - offset < MD5_LENGTH)
+ throw new DigestException("insufficient space in the output " +
+ "buffer to store the digest");
+
+ System.arraycopy(digestBits, 0, buf, offset, MD5_LENGTH);
+
+ init();
+
+ return MD5_LENGTH;
+ }
+
+ /*
+ * Clones this object.
+ */
+ public Object clone() {
+ MD5 that = null;
+ try {
+ that = (MD5) super.clone();
+ that.state = (int[]) this.state.clone();
+ that.transformBuffer = (int[]) this.transformBuffer.clone();
+ that.buffer = (byte[]) this.buffer.clone();
+ that.digestBits = (byte[]) this.digestBits.clone();
+ that.count = this.count;
+ return that;
+ } catch (CloneNotSupportedException e) {
+ }
+ return that;
+ }
+}
diff --git a/base/util/src/netscape/security/provider/RSAPublicKey.java b/base/util/src/netscape/security/provider/RSAPublicKey.java
new file mode 100644
index 000000000..4c65b4fa0
--- /dev/null
+++ b/base/util/src/netscape/security/provider/RSAPublicKey.java
@@ -0,0 +1,152 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.InvalidKeyException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X509Key;
+
+/**
+ * An X.509 public key for the RSA Algorithm.
+ *
+ * @author galperin
+ *
+ * @version $Revision$, $Date$
+ *
+ */
+
+public final class RSAPublicKey extends X509Key implements Serializable {
+
+ /* XXX This currently understands only PKCS#1 RSA Encryption OID
+ and parameter format
+ Later we may consider adding X509v3 OID for RSA keys. Besides
+ different OID it also has a parameter equal to modulus size
+ in bits (redundant!)
+ */
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7764823589128565374L;
+
+ private static final ObjectIdentifier ALGORITHM_OID =
+ AlgorithmId.RSAEncryption_oid;
+
+ private BigInt modulus;
+ private BigInt publicExponent;
+
+ /*
+ * Keep this constructor for backwards compatibility with JDK1.1.
+ */
+ public RSAPublicKey() {
+ }
+
+ /**
+ * Make a RSA public key out of a public exponent and modulus
+ */
+ public RSAPublicKey(BigInt modulus, BigInt publicExponent)
+ throws InvalidKeyException {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ this.algid = new AlgorithmId(ALGORITHM_OID);
+
+ try {
+ DerOutputStream out = new DerOutputStream();
+
+ out.putInteger(modulus);
+ out.putInteger(publicExponent);
+ key = (new DerValue(DerValue.tag_Sequence,
+ out.toByteArray())).toByteArray();
+ encode();
+ } catch (IOException ex) {
+ throw new InvalidKeyException("could not DER encode : " +
+ ex.getMessage());
+ }
+ }
+
+ /**
+ * Make a RSA public key from its DER encoding (X.509).
+ */
+ public RSAPublicKey(byte[] encoded) throws InvalidKeyException {
+ decode(encoded);
+ }
+
+ /**
+ * Get key size as number of bits in modulus
+ * (Always rounded up to a multiple of 8)
+ *
+ */
+ public int getKeySize() {
+ return this.modulus.byteLength() * 8;
+ }
+
+ /**
+ * Get the raw public exponent
+ *
+ */
+ public BigInt getPublicExponent() {
+ return this.publicExponent;
+ }
+
+ /**
+ * Get the raw modulus
+ *
+ */
+ public BigInt getModulus() {
+ return this.modulus;
+ }
+
+ public String toString() {
+ return "RSA Public Key\n Algorithm: " + algid
+ + "\n modulus:\n" + this.modulus.toString() + "\n"
+ + "\n publicExponent:\n" + this.publicExponent.toString()
+ + "\n";
+ }
+
+ protected void parseKeyBits() throws InvalidKeyException {
+ if (!this.algid.getOID().equals(ALGORITHM_OID) &&
+ !this.algid.getOID().equals(AlgorithmId.RSA_oid)) {
+ throw new InvalidKeyException("Key algorithm OID is not RSA");
+ }
+
+ try {
+ DerValue val = new DerValue(key);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new InvalidKeyException("Invalid RSA public key format:" +
+ " must be a SEQUENCE");
+ }
+
+ DerInputStream in = val.data;
+
+ this.modulus = in.getInteger();
+ this.publicExponent = in.getInteger();
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid RSA public key: " +
+ e.getMessage());
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/provider/SHA.java b/base/util/src/netscape/security/provider/SHA.java
new file mode 100644
index 000000000..42a6b8b90
--- /dev/null
+++ b/base/util/src/netscape/security/provider/SHA.java
@@ -0,0 +1,349 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.DigestException;
+import java.security.MessageDigestSpi;
+
+/**
+ * This class implements the Secure Hash Algorithm (SHA) developed by
+ * the National Institute of Standards and Technology along with the
+ * National Security Agency. This is the updated version of SHA
+ * fip-180 as superseded by fip-180-1.
+ *
+ * <p>
+ * It implement JavaSecurity MessageDigest, and can be used by in the Java Security framework, as a pluggable
+ * implementation, as a filter for the digest stream classes.
+ *
+ * @version 1.30 97/12/10
+ * @author Roger Riggs
+ * @author Benjamin Renaud
+ */
+
+public class SHA extends MessageDigestSpi implements Cloneable {
+
+ /* This private hookm controlled by the appropriate constructor,
+ causes this class to implement the first version of SHA,
+ as defined in FIPS 180, as opposed to FIPS 180-1. This was
+ useful for DSA testing. */
+ private int version = 1;
+
+ private static final int SHA_LENGTH = 20;
+
+ // Buffer of int's and count of characters accumulated
+ // 64 bytes are included in each hash block so the low order
+ // bits of count are used to know how to pack the bytes into ints
+ // and to know when to compute the block and start the next one.
+ private int W[] = new int[80];
+ private long count = 0;
+ private final int countmax = 64;
+ private final int countmask = (countmax - 1);
+
+ private int AA, BB, CC, DD, EE;
+
+ SHA(int version) {
+ this();
+ this.version = version;
+ }
+
+ /**
+ * Creates a new SHA object.
+ */
+ public SHA() {
+ init();
+ }
+
+ /**
+ * Return the length of the digest in bytes
+ */
+ protected int engineGetDigestLength() {
+ return (SHA_LENGTH);
+ }
+
+ public void engineUpdate(byte b) {
+ engineUpdate((int) b);
+ }
+
+ /**
+ * Update a byte.
+ *
+ * @param b the byte
+ */
+ private void engineUpdate(int b) {
+ int word;
+ int offset;
+
+ /* compute word offset and bit offset within word the low bits
+ of count are inverted to make put the bytes in the write
+ order */
+ word = ((int) count & countmask) >>> 2;
+ offset = (~(int) count & 3) << 3;
+
+ W[word] = (W[word] & ~(0xff << offset)) | ((b & 0xff) << offset);
+
+ /* If this is the last byte of a block, compute the partial hash */
+ if (((int) count & countmask) == countmask) {
+ computeBlock();
+ }
+ count++;
+ }
+
+ /**
+ * Update a buffer.
+ *
+ * @param b the data to be updated.
+ * @param off the start offset in the data
+ * @param len the number of bytes to be updated.
+ */
+ public void engineUpdate(byte b[], int off, int len) {
+ int word;
+
+ if ((off < 0) || (len < 0) || (off + len > b.length))
+ throw new ArrayIndexOutOfBoundsException();
+
+ // Use single writes until integer aligned
+ while ((len > 0) &&
+ ((int) count & 3) != 0) {
+ engineUpdate(b[off]);
+ off++;
+ len--;
+ }
+
+ /* Assemble groups of 4 bytes to be inserted in integer array */
+ for (; len >= 4; len -= 4, off += 4) {
+
+ word = ((int) count & countmask) >> 2;
+
+ W[word] = ((b[off] & 0xff) << 24) |
+ ((b[off + 1] & 0xff) << 16) |
+ ((b[off + 2] & 0xff) << 8) |
+ ((b[off + 3] & 0xff));
+
+ count += 4;
+ if (((int) count & countmask) == 0) {
+ computeBlock();
+ }
+ }
+
+ /* Use single writes for last few bytes */
+ for (; len > 0; len--, off++) {
+ engineUpdate(b[off]);
+ }
+ }
+
+ /**
+ * Resets the buffers and hash value to start a new hash.
+ */
+ public void init() {
+ AA = 0x67452301;
+ BB = 0xefcdab89;
+ CC = 0x98badcfe;
+ DD = 0x10325476;
+ EE = 0xc3d2e1f0;
+
+ for (int i = 0; i < 80; i++)
+ W[i] = 0;
+ count = 0;
+ }
+
+ /**
+ * Resets the buffers and hash value to start a new hash.
+ */
+ public void engineReset() {
+ init();
+ }
+
+ /**
+ * Computes the final hash and returns the final value as a
+ * byte[20] array. The object is reset to be ready for further
+ * use, as specified in the JavaSecurity MessageDigest
+ * specification.
+ */
+ public byte[] engineDigest() {
+ byte hashvalue[] = new byte[SHA_LENGTH];
+
+ try {
+ engineDigest(hashvalue, 0, hashvalue.length);
+ } catch (DigestException e) {
+ throw new InternalError("");
+ }
+ return hashvalue;
+ }
+
+ /**
+ * Computes the final hash and returns the final value as a
+ * byte[20] array. The object is reset to be ready for further
+ * use, as specified in the JavaSecurity MessageDigest
+ * specification.
+ */
+ public int engineDigest(byte[] hashvalue, int offset, int len)
+ throws DigestException {
+
+ if (len < SHA_LENGTH)
+ throw new DigestException("partial digests not returned");
+ if (hashvalue.length - offset < SHA_LENGTH)
+ throw new DigestException("insufficient space in the output " +
+ "buffer to store the digest");
+
+ /* The number of bits before padding occurs */
+ long bits = count << 3;
+
+ engineUpdate(0x80);
+
+ /* Pad with zeros until length is a multiple of 448 (the last two
+ 32 ints are used a holder for bits (see above). */
+ while ((int) (count & countmask) != 56) {
+ engineUpdate(0);
+ }
+
+ W[14] = (int) (bits >>> 32);
+ W[15] = (int) (bits & 0xffffffff);
+
+ count += 8;
+ computeBlock();
+
+ // Copy out the result
+ hashvalue[offset + 0] = (byte) (AA >>> 24);
+ hashvalue[offset + 1] = (byte) (AA >>> 16);
+ hashvalue[offset + 2] = (byte) (AA >>> 8);
+ hashvalue[offset + 3] = (byte) (AA >>> 0);
+
+ hashvalue[offset + 4] = (byte) (BB >>> 24);
+ hashvalue[offset + 5] = (byte) (BB >>> 16);
+ hashvalue[offset + 6] = (byte) (BB >>> 8);
+ hashvalue[offset + 7] = (byte) (BB >>> 0);
+
+ hashvalue[offset + 8] = (byte) (CC >>> 24);
+ hashvalue[offset + 9] = (byte) (CC >>> 16);
+ hashvalue[offset + 10] = (byte) (CC >>> 8);
+ hashvalue[offset + 11] = (byte) (CC >>> 0);
+
+ hashvalue[offset + 12] = (byte) (DD >>> 24);
+ hashvalue[offset + 13] = (byte) (DD >>> 16);
+ hashvalue[offset + 14] = (byte) (DD >>> 8);
+ hashvalue[offset + 15] = (byte) (DD >>> 0);
+
+ hashvalue[offset + 16] = (byte) (EE >>> 24);
+ hashvalue[offset + 17] = (byte) (EE >>> 16);
+ hashvalue[offset + 18] = (byte) (EE >>> 8);
+ hashvalue[offset + 19] = (byte) (EE >>> 0);
+
+ engineReset(); // remove the evidence
+
+ return SHA_LENGTH;
+ }
+
+ // Constants for each round
+ private final int round1_kt = 0x5a827999;
+ private final int round2_kt = 0x6ed9eba1;
+ private final int round3_kt = 0x8f1bbcdc;
+ private final int round4_kt = 0xca62c1d6;
+
+ /**
+ * Compute a the hash for the current block.
+ *
+ * This is in the same vein as Peter Gutmann's algorithm listed in
+ * the back of Applied Cryptography, Compact implementation of
+ * "old" NIST Secure Hash Algorithm.
+ *
+ */
+ private void computeBlock() {
+ int temp, a, b, c, d, e;
+
+ // The first 16 ints have the byte stream, compute the rest of
+ // the buffer
+ for (int t = 16; t <= 79; t++) {
+ if (version == 0) {
+ W[t] = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+ } else {
+ temp = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+ W[t] = ((temp << 1) | (temp >>> (32 - 1)));
+ }
+ }
+
+ a = AA;
+ b = BB;
+ c = CC;
+ d = DD;
+ e = EE;
+
+ // Round 1
+ for (int i = 0; i < 20; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ ((b & c) | ((~b) & d)) + e + W[i] + round1_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 2
+ for (int i = 20; i < 40; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ (b ^ c ^ d) + e + W[i] + round2_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 3
+ for (int i = 40; i < 60; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ ((b & c) | (b & d) | (c & d)) + e + W[i] + round3_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 4
+ for (int i = 60; i < 80; i++) {
+ temp = ((a << 5) | (a >>> (32 - 5))) +
+ (b ^ c ^ d) + e + W[i] + round4_kt;
+ e = d;
+ d = c;
+ c = ((b << 30) | (b >>> (32 - 30)));
+ b = a;
+ a = temp;
+ }
+ AA += a;
+ BB += b;
+ CC += c;
+ DD += d;
+ EE += e;
+ }
+
+ /*
+ * Clones this object.
+ */
+ public Object clone() {
+ SHA that = null;
+ try {
+ that = (SHA) super.clone();
+ that.W = new int[80];
+ System.arraycopy(this.W, 0, that.W, 0, W.length);
+ return that;
+ } catch (CloneNotSupportedException e) {
+ }
+ return that;
+ }
+}
diff --git a/base/util/src/netscape/security/provider/Sun.java b/base/util/src/netscape/security/provider/Sun.java
new file mode 100644
index 000000000..df384aeab
--- /dev/null
+++ b/base/util/src/netscape/security/provider/Sun.java
@@ -0,0 +1,135 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.Provider;
+
+/**
+ * The SUN Security Provider.
+ *
+ * @author Benjamin Renaud
+ *
+ * @version 1.24, 97/12/10
+ */
+
+/**
+ * Defines the SUN provider.
+ *
+ * Algorithm supported, and their names:
+ *
+ * - SHA-1 is the message digest scheme decribed FIPS 180-1.
+ * Aliases for SHA-1 are SHA.
+ *
+ * - DSA is the signature scheme described in FIPS 186. (SHA used in
+ * DSA is SHA-1: FIPS 186 with Change No 1.) Aliases for DSA are
+ * SHA/DSA, SHA-1/DSA, SHA1/DSA, DSS and the object identifier
+ * strings "OID.1.3.14.3.2.13", "OID.1.3.14.3.2.27" and
+ * "OID.1.2.840.10040.4.3".
+ *
+ * - DSA is the key generation scheme as described in FIPS 186.
+ * Aliases for DSA include the OID strings "OID.1.3.14.3.2.12"
+ * and "OID.1.2.840.10040.4.1".
+ *
+ * - MD5 is the message digest scheme described in RFC 1321.
+ * There are no aliases for MD5.
+ *
+ * Notes: The name of algorithm described in FIPS-180 is SHA-0, and is
+ * not supported by the SUN provider.)
+ */
+public final class Sun extends Provider {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 9134942296334703727L;
+ private static String info = "SUN Security Provider v1.0, " +
+ "DSA signing and key generation, SHA-1 and MD5 message digests.";
+
+ public Sun() {
+ /* We are the SUN provider */
+ super("SUN", 1.0, info);
+
+ try {
+
+ // AccessController.beginPrivileged();
+
+ /*
+ * Signature engines
+ */
+ put("Signature.DSA", "netscape.security.provider.DSA");
+
+ put("Alg.Alias.Signature.SHA/DSA", "DSA");
+ put("Alg.Alias.Signature.SHA1/DSA", "DSA");
+ put("Alg.Alias.Signature.SHA-1/DSA", "DSA");
+ put("Alg.Alias.Signature.DSS", "DSA");
+ put("Alg.Alias.Signature.OID.1.3.14.3.2.13", "DSA");
+ put("Alg.Alias.Signature.OID.1.3.14.3.2.27", "DSA");
+ put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "DSA");
+ // the following are not according to our formal spec but
+ // are still supported
+ put("Alg.Alias.Signature.1.3.14.3.2.13", "DSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.27", "DSA");
+ put("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA");
+ put("Alg.Alias.Signature.SHAwithDSA", "DSA");
+ put("Alg.Alias.Signature.SHA1withDSA", "DSA");
+
+ /*
+ * Key Pair Generator engines
+ */
+ put("KeyPairGenerator.DSA",
+ "netscape.security.provider.DSAKeyPairGenerator");
+
+ put("Alg.Alias.KeyPairGenerator.OID.1.3.14.3.2.12", "DSA");
+ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA");
+ // the following are not according to our formal spec but
+ // are still supported
+ put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA");
+ put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA");
+
+ /*
+ * Digest engines
+ */
+ put("MessageDigest.MD5", "netscape.security.provider.MD5");
+ put("MessageDigest.SHA-1", "netscape.security.provider.SHA");
+
+ put("Alg.Alias.MessageDigest.SHA", "SHA-1");
+ put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+
+ /*
+ * Algorithm Parameter Generator engines
+ */
+ put("AlgorithmParameterGenerator.DSA",
+ "netscape.security.provider.DSAParameterGenerator");
+
+ /*
+ * Algorithm Parameter engines
+ */
+ put("AlgorithmParameters.DSA",
+ "netscape.security.provider.DSAParameters");
+ put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA");
+ /*
+ * Key factories
+ */
+ put("KeyFactory.DSA", "netscape.security.provider.DSAKeyFactory");
+
+ } finally {
+ // AccessController.endPrivileged();
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/provider/X509CertificateFactory.java b/base/util/src/netscape/security/provider/X509CertificateFactory.java
new file mode 100644
index 000000000..9780983a5
--- /dev/null
+++ b/base/util/src/netscape/security/provider/X509CertificateFactory.java
@@ -0,0 +1,61 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.util.Collection;
+
+import netscape.security.x509.X509CRLImpl;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509ExtensionException;
+
+public class X509CertificateFactory extends CertificateFactorySpi {
+
+ public Certificate engineGenerateCertificate(InputStream inStream)
+ throws CertificateException {
+ return new X509CertImpl(inStream);
+ }
+
+ public Collection<Certificate> engineGenerateCertificates(InputStream inStream)
+ throws CertificateException {
+ return null;
+ }
+
+ public CRL engineGenerateCRL(InputStream inStream)
+ throws CRLException {
+ X509CRLImpl crl = null;
+ try {
+ crl = new X509CRLImpl(inStream);
+ } catch (X509ExtensionException e) {
+ ;
+ }
+
+ return crl;
+ }
+
+ public Collection<CRL> engineGenerateCRLs(InputStream inStream)
+ throws CRLException {
+ return null;
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/ASN1CharStrConvMap.java b/base/util/src/netscape/security/util/ASN1CharStrConvMap.java
new file mode 100644
index 000000000..c9c364f4f
--- /dev/null
+++ b/base/util/src/netscape/security/util/ASN1CharStrConvMap.java
@@ -0,0 +1,168 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Maps a ASN.1 character string type to a charset encoder and decoder.
+ * The converter is used to convert a DerValue of a ASN.1 character string type
+ * from bytes to unicode characters and vice versa.
+ *
+ * <p>
+ * A global default ASN1CharStrConvMap is created when the class is initialized. The global default map is extensible.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ *
+ */
+
+public class ASN1CharStrConvMap {
+ // public constructors
+
+ /**
+ * Constructs a ASN1CharStrConvMap.
+ */
+ public ASN1CharStrConvMap() {
+ }
+
+ /**
+ * Get an encoder for the specified DER tag.
+ *
+ * @param tag A DER tag of a ASN.1 character string type,
+ * for example DerValue.tag_PrintableString.
+ *
+ * @return An encoder for the DER tag.
+ */
+ public CharsetEncoder getEncoder(byte tag) {
+ Charset charset = charsets.get(tag);
+ if (charset == null)
+ return null;
+ return charset.newEncoder();
+ }
+
+ /**
+ * Get a decoder for the given DER tag.
+ *
+ * @param tag A DER tag of a ASN.1 character string type,
+ * for example DerValue.tag_PrintableString.
+ *
+ * @return A decoder for the DER tag.
+ */
+ public CharsetDecoder getDecoder(byte tag) {
+ Charset charset = charsets.get(tag);
+ if (charset == null)
+ return null;
+ return charset.newDecoder();
+ }
+
+ /**
+ * Add a tag-charset entry in the map.
+ *
+ * @param tag A DER tag of a ASN.1 character string type,
+ * ex. DerValue.tag_IA5String
+ * @param charset A charset for the tag.
+ */
+ public void addEntry(byte tag, Charset charset) {
+
+ Charset currentCharset = charsets.get(tag);
+
+ if (currentCharset != null) {
+ if (currentCharset != charset) {
+ throw new IllegalArgumentException(
+ "a DER tag to converter entry already exists.");
+ } else {
+ return;
+ }
+ }
+
+ charsets.put(tag, charset);
+ }
+
+ /**
+ * Get an iterator of all tags in the map.
+ *
+ * @return An Iterator of DER tags in the map as Bytes.
+ */
+ public Iterator<Byte> getTags() {
+ return charsets.keySet().iterator();
+ }
+
+ // static public methods.
+
+ /**
+ * Get the global ASN1CharStrConvMap.
+ *
+ * @return The global default ASN1CharStrConvMap.
+ */
+ static public ASN1CharStrConvMap getDefault() {
+ return defaultMap;
+ }
+
+ /**
+ * Set the global default ASN1CharStrConvMap.
+ *
+ * @param newDefault The new default ASN1CharStrConvMap.
+ */
+ static public void setDefault(ASN1CharStrConvMap newDefault) {
+ if (newDefault == null)
+ throw new IllegalArgumentException(
+ "Cannot set a null default Der Tag Converter map");
+ defaultMap = newDefault;
+ }
+
+ // private methods and variables.
+
+ private Map<Byte, Charset> charsets = new HashMap<Byte, Charset>();
+
+ private static ASN1CharStrConvMap defaultMap;
+
+ /**
+ * Create the default converter map on initialization
+ */
+ static {
+ ASN1CharsetProvider provider = new ASN1CharsetProvider();
+
+ defaultMap = new ASN1CharStrConvMap();
+ defaultMap.addEntry(DerValue.tag_PrintableString,
+ provider.charsetForName("ASN.1-Printable"));
+ defaultMap.addEntry(DerValue.tag_VisibleString,
+ provider.charsetForName("ASN.1-Printable"));
+ defaultMap.addEntry(DerValue.tag_IA5String,
+ provider.charsetForName("ASN.1-IA5"));
+ defaultMap.addEntry(DerValue.tag_BMPString,
+ Charset.forName("UnicodeBig"));
+ defaultMap.addEntry(DerValue.tag_UniversalString,
+ provider.charsetForName("ASN.1-Universal"));
+ // XXX this is an oversimplified implementation of T.61 strings, it
+ // doesn't handle all cases
+ defaultMap.addEntry(DerValue.tag_T61String,
+ Charset.forName("ISO-8859-1"));
+ // UTF8String added to ASN.1 in 1998
+ defaultMap.addEntry(DerValue.tag_UTF8String,
+ Charset.forName("UTF-8"));
+ defaultMap.addEntry(DerValue.tag_GeneralString,
+ Charset.forName("UTF-8"));
+ };
+
+};
diff --git a/base/util/src/netscape/security/util/ASN1CharsetProvider.java b/base/util/src/netscape/security/util/ASN1CharsetProvider.java
new file mode 100644
index 000000000..1de1c3c48
--- /dev/null
+++ b/base/util/src/netscape/security/util/ASN1CharsetProvider.java
@@ -0,0 +1,30 @@
+package netscape.security.util;
+
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class ASN1CharsetProvider extends CharsetProvider {
+
+ protected Map<String, Charset> charsets = new HashMap<String, Charset>();
+
+ public ASN1CharsetProvider() {
+ addCharset(new PrintableCharset());
+ addCharset(new IA5Charset());
+ addCharset(new UniversalCharset());
+ }
+
+ public Iterator<Charset> charsets() {
+ return charsets.values().iterator();
+ }
+
+ public Charset charsetForName(String charsetName) {
+ return charsets.get(charsetName);
+ }
+
+ public void addCharset(Charset cs) {
+ charsets.put(cs.name(), cs);
+ }
+}
diff --git a/base/util/src/netscape/security/util/BigInt.java b/base/util/src/netscape/security/util/BigInt.java
new file mode 100644
index 000000000..9210648f1
--- /dev/null
+++ b/base/util/src/netscape/security/util/BigInt.java
@@ -0,0 +1,210 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.math.BigInteger;
+
+/**
+ * A low-overhead arbitrary-precision <em>unsigned</em> integer.
+ * This is intended for use with ASN.1 parsing, and printing of
+ * such parsed values. Convert to "BigInteger" if you need to do
+ * arbitrary precision arithmetic, rather than just represent
+ * the number as a wrapped array of bytes.
+ *
+ * <P>
+ * <em><b>NOTE:</b> This class may eventually disappear, to
+ * be supplanted by big-endian byte arrays which hold both signed
+ * and unsigned arbitrary-precision integers.
+ *
+ * @version 1.23
+ * @author David Brownell
+ */
+public final class BigInt {
+
+ // Big endian -- MSB first.
+ private byte[] places;
+
+ /**
+ * Constructs a "Big" integer from a set of (big-endian) bytes.
+ * Leading zeroes should be stripped off.
+ *
+ * @param data a sequence of bytes, most significant bytes/digits
+ * first. CONSUMED.
+ */
+ public BigInt(byte[] data) {
+ places = data.clone();
+ }
+
+ /**
+ * Constructs a "Big" integer from a "BigInteger", which must be
+ * positive (or zero) in value.
+ */
+ public BigInt(BigInteger i) {
+ byte[] temp = i.toByteArray();
+
+ if ((temp[0] & 0x80) != 0)
+ throw new IllegalArgumentException("negative BigInteger");
+
+ // XXX we assume exactly _one_ sign byte is used...
+
+ if (temp[0] != 0)
+ places = temp;
+ else {
+ // Note that if i = new BigInteger("0"),
+ // i.toByteArray() contains only 1 zero.
+ if (temp.length == 1) {
+ places = new byte[1];
+ places[0] = (byte) 0;
+ } else {
+ places = new byte[temp.length - 1];
+ for (int j = 1; j < temp.length; j++)
+ places[j - 1] = temp[j];
+ }
+ }
+ }
+
+ /**
+ * Constructs a "Big" integer from a normal Java integer.
+ *
+ * @param i the java primitive integer
+ */
+ public BigInt(int i) {
+ if (i < (1 << 8)) {
+ places = new byte[1];
+ places[0] = (byte) i;
+ } else if (i < (1 << 16)) {
+ places = new byte[2];
+ places[0] = (byte) (i >> 8);
+ places[1] = (byte) i;
+ } else if (i < (1 << 24)) {
+ places = new byte[3];
+ places[0] = (byte) (i >> 16);
+ places[1] = (byte) (i >> 8);
+ places[2] = (byte) i;
+ } else {
+ places = new byte[4];
+ places[0] = (byte) (i >> 24);
+ places[1] = (byte) (i >> 16);
+ places[2] = (byte) (i >> 8);
+ places[3] = (byte) i;
+ }
+ }
+
+ /**
+ * Converts the "big" integer to a java primitive integer.
+ *
+ * @exception NumberFormatException if 32 bits is insufficient.
+ */
+ public int toInt() {
+ if (places.length > 4)
+ throw new NumberFormatException("BigInt.toInt, too big");
+ int retval = 0, i = 0;
+ for (; i < places.length; i++)
+ retval = (retval << 8) + ((int) places[i] & 0xff);
+ return retval;
+ }
+
+ /**
+ * Returns a hexadecimal printed representation. The value is
+ * formatted to fit on lines of at least 75 characters, with
+ * embedded newlines. Words are separated for readability,
+ * with eight words (32 bytes) per line.
+ */
+ public String toString() {
+ return hexify();
+ }
+
+ /**
+ * Returns a BigInteger value which supports many arithmetic
+ * operations. Assumes negative values will never occur.
+ */
+ public BigInteger toBigInteger() {
+ return new BigInteger(1, places);
+ }
+
+ /**
+ * Returns the length of the data as a byte array.
+ */
+ public int byteLength() {
+ return places.length;
+ }
+
+ /**
+ * Returns the data as a byte array. The most significant bit
+ * of the array is bit zero (as in <code>java.math.BigInteger</code>).
+ */
+ public byte[] toByteArray() {
+ if (places.length == 0) {
+ byte zero[] = new byte[1];
+ zero[0] = (byte) 0;
+ return zero;
+ } else {
+ return places.clone();
+ }
+ }
+
+ private static final String digits = "0123456789abcdef";
+
+ private String hexify() {
+ if (places.length == 0)
+ return " 0 ";
+
+ StringBuffer buf = new StringBuffer(places.length * 2);
+ buf.append(" "); // four spaces
+ for (int i = 0; i < places.length; i++) {
+ buf.append(digits.charAt((places[i] >> 4) & 0x0f));
+ buf.append(digits.charAt(places[i] & 0x0f));
+ if (((i + 1) % 32) == 0) {
+ if ((i + 1) != places.length)
+ buf.append("\n "); // line after four words
+ } else if (((i + 1) % 4) == 0)
+ buf.append(' '); // space between words
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns true iff the parameter is a numerically equivalent
+ * BigInt.
+ *
+ * @param other the object being compared with this one.
+ */
+ public boolean equals(Object other) {
+ if (other instanceof BigInt)
+ return equals((BigInt) other);
+ return false;
+ }
+
+ /**
+ * Returns true iff the parameter is numerically equivalent.
+ *
+ * @param other the BigInt being compared with this one.
+ */
+ public boolean equals(BigInt other) {
+ if (this == other)
+ return true;
+
+ byte[] otherPlaces = other.toByteArray();
+ if (places.length != otherPlaces.length)
+ return false;
+ for (int i = 0; i < places.length; i++)
+ if (places[i] != otherPlaces[i])
+ return false;
+ return true;
+ }
+}
diff --git a/base/util/src/netscape/security/util/BitArray.java b/base/util/src/netscape/security/util/BitArray.java
new file mode 100644
index 000000000..ab77c226e
--- /dev/null
+++ b/base/util/src/netscape/security/util/BitArray.java
@@ -0,0 +1,257 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * A packed array of booleans.
+ *
+ * @author Joshua Bloch
+ * @author Douglas Hoover
+ * @version 1.2 97/12/10
+ */
+
+public class BitArray {
+
+ private byte[] repn;
+ private int length;
+
+ private static final int BITS_PER_UNIT = 8;
+
+ private static int subscript(int idx) {
+ return idx / BITS_PER_UNIT;
+ }
+
+ private static int position(int idx) { // bits big-endian in each unit
+ return 1 << (BITS_PER_UNIT - 1 - (idx % BITS_PER_UNIT));
+ }
+
+ /**
+ * Creates a BitArray of the specified size, initialized to zeros.
+ */
+ public BitArray(int length) throws IllegalArgumentException {
+ if (length < 0) {
+ throw new IllegalArgumentException("Negative length for BitArray");
+ }
+
+ this.length = length;
+
+ repn = new byte[(length + BITS_PER_UNIT - 1) / BITS_PER_UNIT];
+ }
+
+ /**
+ * Creates a BitArray of the specified size, initialized from the
+ * specified byte array. The most significant bit of a[0] gets
+ * index zero in the BitArray. The array a must be large enough
+ * to specify a value for every bit in the BitArray. In other words,
+ * 8*a.length >= length.
+ */
+ public BitArray(int length, byte[] a) throws IllegalArgumentException {
+
+ if (length < 0) {
+ throw new IllegalArgumentException("Negative length for BitArray");
+ }
+ if (a.length * BITS_PER_UNIT < length) {
+ throw new IllegalArgumentException("Byte array too short to represent " +
+ "bit array of given length");
+ }
+
+ this.length = length;
+
+ int repLength = ((length + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
+ int unusedBits = repLength * BITS_PER_UNIT - length;
+ byte bitMask = (byte) (0xFF << unusedBits);
+
+ /*
+ normalize the representation:
+ 1. discard extra bytes
+ 2. zero out extra bits in the last byte
+ */
+ repn = new byte[repLength];
+ System.arraycopy(a, 0, repn, 0, repLength);
+ if (repn.length > 0)
+ repn[repn.length - 1] = (byte) (repn[repn.length - 1] & bitMask);
+ }
+
+ /**
+ * Create a BitArray whose bits are those of the given array
+ * of Booleans.
+ */
+ public BitArray(boolean[] bits) {
+ length = bits.length;
+ repn = new byte[(length + 7) / 8];
+
+ for (int i = 0; i < length; i++) {
+ set(i, bits[i]);
+ }
+ }
+
+ /**
+ * Copy constructor (for cloning).
+ */
+ private BitArray(BitArray ba) {
+ length = ba.length;
+ repn = (byte[]) ba.repn.clone();
+ }
+
+ /**
+ * Returns the indexed bit in this BitArray.
+ */
+ public boolean get(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= length) {
+ throw new ArrayIndexOutOfBoundsException(Integer.toString(index));
+ }
+
+ return (repn[subscript(index)] & position(index)) != 0;
+ }
+
+ /**
+ * Sets the indexed bit in this BitArray.
+ */
+ public void set(int index, boolean value)
+ throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= length) {
+ throw new ArrayIndexOutOfBoundsException(Integer.toString(index));
+ }
+ int idx = subscript(index);
+ int bit = position(index);
+
+ if (value) {
+ repn[idx] |= bit;
+ } else {
+ repn[idx] &= ~bit;
+ }
+ }
+
+ /**
+ * Returns the length of this BitArray.
+ */
+ public int length() {
+ return length;
+ }
+
+ /**
+ * Returns a Byte array containing the contents of this BitArray.
+ * The bit stored at index zero in this BitArray will be copied
+ * into the most significant bit of the zeroth element of the
+ * returned byte array. The last byte of the returned byte array
+ * will be contain zeros in any bits that do not have corresponding
+ * bits in the BitArray. (This matters only if the BitArray's size
+ * is not a multiple of 8.)
+ */
+ public byte[] toByteArray() {
+ return (byte[]) repn.clone();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (obj == null || !(obj instanceof BitArray))
+ return false;
+
+ BitArray ba = (BitArray) obj;
+
+ if (ba.length != length)
+ return false;
+
+ for (int i = 0; i < repn.length; i += 1) {
+ if (repn[i] != ba.repn[i])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return a boolean array with the same bit values a this BitArray.
+ */
+ public boolean[] toBooleanArray() {
+ boolean[] bits = new boolean[length];
+
+ for (int i = 0; i < length; i++) {
+ bits[i] = get(i);
+ }
+ return bits;
+ }
+
+ /**
+ * Returns a hash code value for this bit array.
+ *
+ * @return a hash code value for this bit array.
+ */
+ public int hashCode() {
+ int hashCode = 0;
+
+ for (int i = 0; i < repn.length; i++)
+ hashCode = 31 * hashCode + repn[i];
+
+ return hashCode ^ length;
+ }
+
+ public Object clone() {
+ return new BitArray(this);
+ }
+
+ private static final byte[][] NYBBLE = {
+ { (byte) '0', (byte) '0', (byte) '0', (byte) '0' },
+ { (byte) '0', (byte) '0', (byte) '0', (byte) '1' },
+ { (byte) '0', (byte) '0', (byte) '1', (byte) '0' },
+ { (byte) '0', (byte) '0', (byte) '1', (byte) '1' },
+ { (byte) '0', (byte) '1', (byte) '0', (byte) '0' },
+ { (byte) '0', (byte) '1', (byte) '0', (byte) '1' },
+ { (byte) '0', (byte) '1', (byte) '1', (byte) '0' },
+ { (byte) '0', (byte) '1', (byte) '1', (byte) '1' },
+ { (byte) '1', (byte) '0', (byte) '0', (byte) '0' },
+ { (byte) '1', (byte) '0', (byte) '0', (byte) '1' },
+ { (byte) '1', (byte) '0', (byte) '1', (byte) '0' },
+ { (byte) '1', (byte) '0', (byte) '1', (byte) '1' },
+ { (byte) '1', (byte) '1', (byte) '0', (byte) '0' },
+ { (byte) '1', (byte) '1', (byte) '0', (byte) '1' },
+ { (byte) '1', (byte) '1', (byte) '1', (byte) '0' },
+ { (byte) '1', (byte) '1', (byte) '1', (byte) '1' }
+ };
+
+ private static final int BYTES_PER_LINE = 8;
+
+ /**
+ * Returns a string representation of this BitArray.
+ */
+ public String toString() {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ for (int i = 0; i < repn.length - 1; i++) {
+ out.write(NYBBLE[(repn[i] >> 4) & 0x0F], 0, 4);
+ out.write(NYBBLE[repn[i] & 0x0F], 0, 4);
+
+ if (i % BYTES_PER_LINE == BYTES_PER_LINE - 1) {
+ out.write('\n');
+ } else {
+ out.write(' ');
+ }
+ }
+
+ // in last byte of repn, use only the valid bits
+ for (int i = BITS_PER_UNIT * (repn.length - 1); i < length; i++) {
+ out.write(get(i) ? '1' : '0');
+ }
+
+ return new String(out.toByteArray());
+
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/ByteArrayLexOrder.java b/base/util/src/netscape/security/util/ByteArrayLexOrder.java
new file mode 100644
index 000000000..2ee2f740e
--- /dev/null
+++ b/base/util/src/netscape/security/util/ByteArrayLexOrder.java
@@ -0,0 +1,58 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.util.Comparator;
+
+/**
+ * Compare two byte arrays in lexicographical order.
+ *
+ * @version 1.4 97/12/10
+ * @author D. N. Hoover
+ */
+public class ByteArrayLexOrder implements Comparator<byte[]> {
+
+ /**
+ * Perform lexicographical comparison of two byte arrays,
+ * regarding each byte as unsigned. That is, compare array entries
+ * in order until they differ--the array with the smaller entry
+ * is "smaller". If array entries are
+ * equal till one array ends, then the longer array is "bigger".
+ *
+ * @param obj1 first byte array to compare.
+ * @param obj2 second byte array to compare.
+ * @return negative number if obj1 < obj2, 0 if obj1 == obj2,
+ * positive number if obj1 > obj2.
+ *
+ * @exception <code>ClassCastException</code> if either argument is not a byte array.
+ */
+ public final int compare(byte[] bytes1, byte[] bytes2) {
+
+ int diff;
+ for (int i = 0; i < bytes1.length && i < bytes2.length; i++) {
+ diff = (bytes1[i] & 0xFF) - (bytes2[i] & 0xFF);
+ if (diff != 0) {
+ return diff;
+ }
+ }
+ // if array entries are equal till the first ends, then the
+ // longer is "bigger"
+ return bytes1.length - bytes2.length;
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/ByteArrayTagOrder.java b/base/util/src/netscape/security/util/ByteArrayTagOrder.java
new file mode 100644
index 000000000..e57a3b5f1
--- /dev/null
+++ b/base/util/src/netscape/security/util/ByteArrayTagOrder.java
@@ -0,0 +1,44 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.util.Comparator;
+
+public class ByteArrayTagOrder implements Comparator<byte[]> {
+
+ /**
+ * Compare two byte arrays, by the order of their tags,
+ * as defined in ITU-T X.680, sec. 6.4. (First compare
+ * tag classes, then tag numbers, ignoring the constructivity bit.)
+ *
+ * @param obj1 first byte array to compare.
+ * @param obj2 second byte array to compare.
+ * @return negative number if obj1 < obj2, 0 if obj1 == obj2,
+ * positive number if obj1 > obj2.
+ *
+ * @exception <code>ClassCastException</code> if either argument is not a byte array.
+ */
+
+ public final int compare(byte[] bytes1, byte[] bytes2) {
+
+ // tag order is same as byte order ignoring any difference in
+ // the constructivity bit (0x02)
+ return (bytes1[0] | 0x20) - (bytes2[0] | 0x20);
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/CertPrettyPrint.java b/base/util/src/netscape/security/util/CertPrettyPrint.java
new file mode 100644
index 000000000..3a8c65fd0
--- /dev/null
+++ b/base/util/src/netscape/security/util/CertPrettyPrint.java
@@ -0,0 +1,345 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.text.DateFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+
+import netscape.security.x509.CertificateExtensions;
+import netscape.security.x509.CertificateX509Key;
+import netscape.security.x509.Extension;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.pkcs7.ContentInfo;
+import org.mozilla.jss.pkcs7.SignedData;
+
+/**
+ * This class will display the certificate content in predefined
+ * format.
+ *
+ * @author Jack Pan-Chen
+ * @version $Revision$, $Date$
+ */
+public class CertPrettyPrint {
+
+ /*==========================================================
+ * constants
+ *==========================================================*/
+ private final static String CUSTOM_LOCALE = "Custom";
+
+ /*==========================================================
+ * variables
+ *==========================================================*/
+ private X509CertImpl mX509Cert = null;
+ private Certificate mCert = null;
+ private PrettyPrintFormat pp = null;
+ private byte[] mCert_b = null;
+
+ /*==========================================================
+ * constructors
+ *==========================================================*/
+
+ public CertPrettyPrint(Certificate cert) {
+ if (cert instanceof X509CertImpl)
+ mX509Cert = (X509CertImpl) cert;
+
+ pp = new PrettyPrintFormat(":");
+ }
+
+ public CertPrettyPrint(byte[] certb) {
+ mCert_b = certb;
+ pp = new PrettyPrintFormat(":");
+ }
+
+ /*==========================================================
+ * public methods
+ *==========================================================*/
+
+ /**
+ * This method return string representation of the certificate
+ * in predefined format using specified client local. I18N Support.
+ *
+ * @param clientLocale Locale to be used for localization
+ * @return string representation of the certificate
+ */
+ public String toString(Locale clientLocale) {
+
+ if (mX509Cert != null)
+ return X509toString(clientLocale);
+ else if (mCert_b != null)
+ return pkcs7toString(clientLocale);
+ else
+ return null;
+ }
+
+ public String pkcs7toString(Locale clientLocale) {
+ String content = "";
+
+ try {
+ mX509Cert = new X509CertImpl(mCert_b);
+ return toString(clientLocale);
+ } catch (Exception e) {
+ }
+
+ ContentInfo ci = null;
+ try {
+ ci = (ContentInfo)
+ ASN1Util.decode(ContentInfo.getTemplate(), mCert_b);
+ } catch (Exception e) {
+ return "";
+ }
+
+ if (ci.getContentType().equals(ContentInfo.SIGNED_DATA)) {
+ SignedData sd = null;
+ try {
+ sd = (SignedData) ci.getInterpretedContent();
+ } catch (Exception e) {
+ return "";
+ }
+
+ if (sd.hasCertificates()) {
+ SET certs = sd.getCertificates();
+
+ for (int i = 0; i < certs.size(); i++) {
+ org.mozilla.jss.pkix.cert.Certificate cert =
+ (org.mozilla.jss.pkix.cert.Certificate) certs.elementAt(i);
+ X509CertImpl certImpl = null;
+ try {
+ certImpl = new X509CertImpl(
+ ASN1Util.encode(cert));
+ } catch (Exception e) {
+ }
+
+ CertPrettyPrint print = new CertPrettyPrint(certImpl);
+ content += print.toString(Locale.getDefault());
+ content += "\n";
+ }
+
+ return content;
+ }
+ }
+
+ return content;
+ }
+
+ public String stripCertBrackets(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if ((s.startsWith("-----BEGIN CERTIFICATE-----")) &&
+ (s.endsWith("-----END CERTIFICATE-----"))) {
+ return (s.substring(27, (s.length() - 25)));
+ }
+
+ // To support Thawte's header and footer
+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----")) &&
+ (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) {
+ return (s.substring(35, (s.length() - 33)));
+ }
+
+ return s;
+ }
+
+ public String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\n') {
+ continue;
+ } else if (s.charAt(i) == '\r') {
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ public String X509toString(Locale clientLocale) {
+
+ //get I18N resources
+ ResourceBundle resource = ResourceBundle.getBundle(
+ PrettyPrintResources.class.getName());
+ DateFormat dateFormater = DateFormat.getDateTimeInstance(
+ DateFormat.FULL, DateFormat.FULL, clientLocale);
+ //get timezone and timezone ID
+ String tz = " ";
+ String tzid = " ";
+
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ X509CertInfo info = (X509CertInfo) mX509Cert.get(
+ X509CertImpl.NAME + "." + X509CertImpl.INFO);
+ String serial2 = mX509Cert.getSerialNumber().toString(16).toUpperCase();
+
+ //get correct instance of key
+ PublicKey pKey = mX509Cert.getPublicKey();
+ X509Key key = null;
+
+ if (pKey instanceof CertificateX509Key) {
+ CertificateX509Key certKey = (CertificateX509Key) pKey;
+
+ key = (X509Key) certKey.get(CertificateX509Key.KEY);
+ }
+ if (pKey instanceof X509Key) {
+ key = (X509Key) pKey;
+ }
+
+ //take care of spki
+ sb.append(pp.indent(4) + resource.getString(
+ PrettyPrintResources.TOKEN_CERTIFICATE) + "\n");
+ sb.append(pp.indent(8) + resource.getString(
+ PrettyPrintResources.TOKEN_DATA) + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_VERSION) + " v");
+ sb.append((mX509Cert.getVersion() + 1) + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SERIAL) + "0x" + serial2 + "\n");
+ //XXX I18N Algorithm Name ?
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGALG) + mX509Cert.getSigAlgName() +
+ " - " + mX509Cert.getSigAlgOID() + "\n");
+ //XXX I18N IssuerDN ?
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_ISSUER) +
+ mX509Cert.getIssuerDN().toString() + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_VALIDITY) + "\n");
+ String notBefore = dateFormater.format(mX509Cert.getNotBefore());
+ String notAfter = dateFormater.format(mX509Cert.getNotAfter());
+
+ //get timezone and timezone ID
+ if (TimeZone.getDefault() != null) {
+ tz = TimeZone.getDefault().getDisplayName(
+ TimeZone.getDefault().inDaylightTime(
+ mX509Cert.getNotBefore()),
+ TimeZone.SHORT,
+ clientLocale);
+ tzid = TimeZone.getDefault().getID();
+ }
+ // Specify notBefore
+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) {
+ // Do NOT append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NOT_BEFORE)
+ + notBefore
+ + "\n");
+ } else {
+ // Append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NOT_BEFORE)
+ + notBefore
+ + " " + tzid + "\n");
+ }
+ // re-get timezone (just in case it is different . . .)
+ if (TimeZone.getDefault() != null) {
+ tz = TimeZone.getDefault().getDisplayName(
+ TimeZone.getDefault().inDaylightTime(
+ mX509Cert.getNotAfter()),
+ TimeZone.SHORT,
+ clientLocale);
+ }
+ // Specify notAfter
+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) {
+ // Do NOT append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NOT_AFTER)
+ + notAfter
+ + "\n");
+ } else {
+ // Append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NOT_AFTER)
+ + notAfter
+ + " " + tzid + "\n");
+ }
+ //XXX I18N SubjectDN ?
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SUBJECT) +
+ mX509Cert.getSubjectDN().toString() + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SPKI) + "\n");
+
+ PubKeyPrettyPrint pkpp = new PubKeyPrettyPrint(key);
+
+ sb.append(pkpp.toString(clientLocale, 16, 16));
+
+ //take care of extensions
+ CertificateExtensions extensions = (CertificateExtensions)
+ info.get(X509CertInfo.EXTENSIONS);
+
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n");
+ if (extensions != null)
+ for (int i = 0; i < extensions.size(); i++) {
+ Extension ext = (Extension) extensions.elementAt(i);
+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 16);
+
+ sb.append(extpp.toString());
+ }
+
+ //take care of signature
+ sb.append(pp.indent(8) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n");
+ //XXX I18N Algorithm Name ?
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_ALGORITHM) +
+ mX509Cert.getSigAlgName() + " - " + mX509Cert.getSigAlgOID() + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n");
+ sb.append(pp.toHexString(mX509Cert.getSignature(), 16, 16));
+
+ // fingerprints
+ String[] hashes = new String[] { "MD2", "MD5", "SHA1", "SHA256", "SHA512" };
+ String certFingerprints = "";
+
+ sb.append(pp.indent(8) + "FingerPrint\n");
+ for (int i = 0; i < hashes.length; i++) {
+ MessageDigest md = MessageDigest.getInstance(hashes[i]);
+
+ md.update(mX509Cert.getEncoded());
+ certFingerprints += pp.indent(12) + hashes[i] + ":\n" +
+ pp.toHexString(md.digest(), 16, 16);
+ }
+
+ sb.append(certFingerprints);
+ } catch (Exception e) {
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/CrlPrettyPrint.java b/base/util/src/netscape/security/util/CrlPrettyPrint.java
new file mode 100644
index 000000000..edf1217ea
--- /dev/null
+++ b/base/util/src/netscape/security/util/CrlPrettyPrint.java
@@ -0,0 +1,271 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.text.DateFormat;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TimeZone;
+
+import netscape.security.x509.CRLExtensions;
+import netscape.security.x509.Extension;
+import netscape.security.x509.RevokedCertificate;
+import netscape.security.x509.X509CRLImpl;
+
+/**
+ * This class will display the certificate content in predefined
+ * format.
+ *
+ * @author Andrew Wnuk
+ * @version $Revision$, $Date$
+ */
+public class CrlPrettyPrint {
+
+ /*==========================================================
+ * constants
+ *==========================================================*/
+ private final static String CUSTOM_LOCALE = "Custom";
+
+ /*==========================================================
+ * variables
+ *==========================================================*/
+ private X509CRLImpl mCRL = null;
+ private PrettyPrintFormat pp = null;
+
+ /*==========================================================
+ * constructors
+ *==========================================================*/
+
+ public CrlPrettyPrint(X509CRLImpl crl) {
+ mCRL = crl;
+ pp = new PrettyPrintFormat(":");
+ }
+
+ /*==========================================================
+ * public methods
+ *==========================================================*/
+
+ /**
+ * This method return string representation of the certificate
+ * revocation list in predefined format using specified client
+ * local. I18N Support.
+ *
+ * @param clientLocale Locale to be used for localization
+ * @return string representation of the certificate
+ */
+ public String toString(Locale clientLocale) {
+ return toString(clientLocale, 0, 0, 0);
+ }
+
+ public String toString(Locale clientLocale, long crlSize, long pageStart, long pageSize) {
+
+ //get I18N resources
+ ResourceBundle resource = ResourceBundle.getBundle(
+ PrettyPrintResources.class.getName());
+ DateFormat dateFormater = DateFormat.getDateTimeInstance(
+ DateFormat.FULL, DateFormat.FULL, clientLocale);
+ //get timezone and timezone ID
+ String tz = " ";
+ String tzid = " ";
+
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(4) + resource.getString(
+ PrettyPrintResources.TOKEN_CRL) + "\n");
+ sb.append(pp.indent(8) + resource.getString(
+ PrettyPrintResources.TOKEN_DATA) + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_VERSION) + " v");
+ sb.append((mCRL.getVersion() + 1) + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGALG) + mCRL.getSigAlgName() +
+ " - " + mCRL.getSigAlgOID() + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_ISSUER) +
+ mCRL.getIssuerDN().toString() + "\n");
+ // Format thisUpdate
+ String thisUpdate = dateFormater.format(mCRL.getThisUpdate());
+
+ // get timezone and timezone ID
+ if (TimeZone.getDefault() != null) {
+ tz = TimeZone.getDefault().getDisplayName(
+ TimeZone.getDefault().inDaylightTime(
+ mCRL.getThisUpdate()),
+ TimeZone.SHORT,
+ clientLocale);
+ tzid = TimeZone.getDefault().getID();
+ }
+ // Specify ThisUpdate
+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) {
+ // Do NOT append timezone ID
+ sb.append(pp.indent(12)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_THIS_UPDATE)
+ + thisUpdate
+ + "\n");
+ } else {
+ // Append timezone ID
+ sb.append(pp.indent(12)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_THIS_UPDATE)
+ + thisUpdate
+ + " " + tzid + "\n");
+ }
+ // Check for presence of NextUpdate
+ if (mCRL.getNextUpdate() != null) {
+ // Format nextUpdate
+ String nextUpdate = dateFormater.format(mCRL.getNextUpdate());
+
+ // re-get timezone (just in case it is different . . .)
+ if (TimeZone.getDefault() != null) {
+ tz = TimeZone.getDefault().getDisplayName(
+ TimeZone.getDefault().inDaylightTime(
+ mCRL.getNextUpdate()),
+ TimeZone.SHORT,
+ clientLocale);
+ }
+ // Specify NextUpdate
+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) {
+ // Do NOT append timezone ID
+ sb.append(pp.indent(12)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NEXT_UPDATE)
+ + nextUpdate
+ + "\n");
+ } else {
+ // Append timezone ID
+ sb.append(pp.indent(12)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_NEXT_UPDATE)
+ + nextUpdate
+ + " " + tzid + "\n");
+ }
+ }
+
+ if (crlSize > 0 && pageStart == 0 && pageSize == 0) {
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES) + crlSize + "\n");
+ } else if ((crlSize == 0 && pageStart == 0 && pageSize == 0) ||
+ (crlSize > 0 && pageStart > 0 && pageSize > 0)) {
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES));
+ if (crlSize > 0 && pageStart > 0 && pageSize > 0) {
+ long upperLimit = (pageStart + pageSize - 1 > crlSize) ? crlSize : pageStart + pageSize - 1;
+
+ sb.append("" + pageStart + "-" + upperLimit + " of " + crlSize);
+ }
+ sb.append("\n");
+
+ Set<RevokedCertificate> revokedCerts = mCRL.getRevokedCertificates();
+
+ if (revokedCerts != null) {
+ Iterator<RevokedCertificate> i = revokedCerts.iterator();
+ long l = 1;
+
+ while ((i.hasNext()) && ((crlSize == 0) || (pageStart + pageSize > l))) {
+ RevokedCertificate revokedCert = i.next();
+
+ if ((crlSize == 0) || ((pageStart <= l) && (pageStart + pageSize > l))) {
+ sb.append(pp.indent(16) + resource.getString(
+ PrettyPrintResources.TOKEN_SERIAL) + "0x" +
+ revokedCert.getSerialNumber().toString(16).toUpperCase() + "\n");
+ String revocationDate =
+ dateFormater.format(revokedCert.getRevocationDate());
+
+ // re-get timezone
+ // (just in case it is different . . .)
+ if (TimeZone.getDefault() != null) {
+ tz = TimeZone.getDefault().getDisplayName(
+ TimeZone.getDefault().inDaylightTime(
+ revokedCert.getRevocationDate()),
+ TimeZone.SHORT,
+ clientLocale);
+ }
+ // Specify revocationDate
+ if (tz.equals(tzid) ||
+ tzid.equals(CUSTOM_LOCALE)) {
+ // Do NOT append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_REVOCATION_DATE)
+ + revocationDate
+ + "\n");
+ } else {
+ // Append timezone ID
+ sb.append(pp.indent(16)
+ + resource.getString(
+ PrettyPrintResources.TOKEN_REVOCATION_DATE)
+ + revocationDate
+ + " " + tzid + "\n");
+ }
+ if (revokedCert.hasExtensions()) {
+ sb.append(pp.indent(16) + resource.getString(
+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n");
+ CRLExtensions crlExtensions = revokedCert.getExtensions();
+
+ if (crlExtensions != null) {
+ for (int k = 0; k < crlExtensions.size(); k++) {
+ Extension ext = (Extension) crlExtensions.elementAt(k);
+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 20);
+
+ sb.append(extpp.toString());
+ }
+ }
+ }
+ }
+ l++;
+ }
+ }
+ }
+
+ CRLExtensions crlExtensions = mCRL.getExtensions();
+
+ if (crlExtensions != null) {
+ sb.append(pp.indent(8) + resource.getString(
+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n");
+ for (int k = 0; k < crlExtensions.size(); k++) {
+ Extension ext = (Extension) crlExtensions.elementAt(k);
+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 12);
+
+ sb.append(extpp.toString());
+ }
+ }
+
+ //take care of signature
+ sb.append(pp.indent(8) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n");
+ //XXX I18N Algorithm Name ?
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_ALGORITHM) +
+ mCRL.getSigAlgName() + " - " + mCRL.getSigAlgOID() + "\n");
+ sb.append(pp.indent(12) + resource.getString(
+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n");
+ sb.append(pp.toHexString(mCRL.getSignature(), 16, 16));
+
+ } catch (Exception e) {
+ sb.append("\n\n" + pp.indent(4) + resource.getString(
+ PrettyPrintResources.TOKEN_DECODING_ERROR) + "\n\n");
+ e.printStackTrace();
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/base/util/src/netscape/security/util/DerEncoder.java b/base/util/src/netscape/security/util/DerEncoder.java
new file mode 100644
index 000000000..c2eb64fc0
--- /dev/null
+++ b/base/util/src/netscape/security/util/DerEncoder.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Interface to an object that knows how to write its own DER
+ * encoding to an output stream.
+ *
+ * @version 1.2 97/12/10
+ * @author D. N. Hoover
+ */
+public interface DerEncoder {
+
+ /**
+ * DER encode this object and write the results to a stream.
+ *
+ * @param out the stream on which the DER encoding is written.
+ */
+ public void derEncode(OutputStream out)
+ throws IOException;
+
+}
diff --git a/base/util/src/netscape/security/util/DerInputBuffer.java b/base/util/src/netscape/security/util/DerInputBuffer.java
new file mode 100644
index 000000000..7534f3d06
--- /dev/null
+++ b/base/util/src/netscape/security/util/DerInputBuffer.java
@@ -0,0 +1,186 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * DER input buffer ... this is the main abstraction in the DER library
+ * which actively works with the "untyped byte stream" abstraction. It
+ * does so with impunity, since it's not intended to be exposed to the
+ * anyone who could violate the "typed value stream" DER model and hence
+ * corrupt the input stream of DER values.
+ *
+ * @version 1.11
+ * @author David Brownell
+ */
+class DerInputBuffer extends ByteArrayInputStream implements Cloneable {
+
+ DerInputBuffer(byte[] buf) {
+ super(buf);
+ }
+
+ DerInputBuffer(byte[] buf, int offset, int len) {
+ super(buf, offset, len);
+ }
+
+ DerInputBuffer dup() {
+ try {
+ DerInputBuffer retval = (DerInputBuffer) clone();
+
+ retval.mark(Integer.MAX_VALUE);
+ return retval;
+ } catch (CloneNotSupportedException e) {
+ throw new IllegalArgumentException(e.toString());
+ }
+ }
+
+ byte[] toByteArray() {
+ int len = available();
+ if (len <= 0)
+ return null;
+ byte[] retval = new byte[len];
+
+ System.arraycopy(buf, pos, retval, 0, len);
+ return retval;
+ }
+
+ int peek() throws IOException {
+ if (pos >= count)
+ throw new IOException("out of data");
+ else
+ return buf[pos];
+ }
+
+ /**
+ * Compares this DerInputBuffer for equality with the specified
+ * object.
+ */
+ public boolean equals(Object other) {
+ if (other instanceof DerInputBuffer)
+ return equals((DerInputBuffer) other);
+ else
+ return false;
+ }
+
+ boolean equals(DerInputBuffer other) {
+ if (this == other)
+ return true;
+
+ int max = this.available();
+ if (other.available() != max)
+ return false;
+ for (int i = 0; i < max; i++) {
+ if (this.buf[this.pos + i] != other.buf[other.pos + i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void truncate(int len) throws IOException {
+ if (len > available())
+ throw new IOException("insufficient data");
+ count = pos + len;
+ }
+
+ /**
+ * Returns the unsigned integer which takes up the specified number
+ * of bytes in this buffer.
+ */
+ BigInt getUnsigned(int len) throws IOException {
+ if (len > available())
+ throw new IOException("short read, getInteger");
+
+ /*
+ * A prepended zero is used to ensure that the integer is
+ * interpreted as unsigned even when the high order bit is
+ * zero. We don't support signed BigInts.
+ *
+ * Fix this here ... BigInts aren't expected to have these,
+ * and stuff like signing (sigsize = f(modulus)) misbehaves.
+ */
+ if (len > 1 && buf[pos] == 0) {
+ len--;
+ skip(1);
+ }
+
+ /*
+ * Consume the rest of the buffer, returning its value as
+ * an unsigned integer.
+ */
+ byte[] bytes = new byte[len];
+
+ System.arraycopy(buf, pos, bytes, 0, len);
+ skip(len);
+ return new BigInt(bytes);
+ }
+
+ /**
+ * Returns the bit string which takes up the rest of this buffer.
+ * This bit string must be byte-aligned.
+ */
+ byte[] getBitString() {
+ if (pos >= count || buf[pos] != 0)
+ return null;
+ /*
+ * Just copy the data into an aligned, padded octet buffer,
+ * and consume the rest of the buffer.
+ */
+ int len = available();
+ byte[] retval = new byte[len - 1];
+
+ System.arraycopy(buf, pos + 1, retval, 0, len - 1);
+ pos = count;
+ return retval;
+ }
+
+ /**
+ * Returns the bit string which takes up the rest of this buffer.
+ * The bit string need not be byte-aligned.
+ */
+ BitArray getUnalignedBitString() {
+ if (pos >= count)
+ return null;
+ /*
+ * Just copy the data into an aligned, padded octet buffer,
+ * and consume the rest of the buffer.
+ */
+ int len = available();
+ byte[] bits = new byte[len - 1];
+ int length = bits.length * 8 - buf[pos]; // number of valid bits
+
+ System.arraycopy(buf, pos + 1, bits, 0, len - 1);
+
+ BitArray bitArray = new BitArray(length, bits);
+ pos = count;
+ return bitArray;
+ }
+
+ /**
+ * Package-access method to optimize output operations
+ */
+ void dump(OutputStream out, int length) throws IOException {
+ if (count < mark + length)
+ throw new IOException("short DER value (encode)");
+ out.write(buf, mark, length);
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/DerInputStream.java b/base/util/src/netscape/security/util/DerInputStream.java
new file mode 100644
index 000000000..20ced6757
--- /dev/null
+++ b/base/util/src/netscape/security/util/DerInputStream.java
@@ -0,0 +1,662 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import java.util.Vector;
+
+/**
+ * A DER input stream, used for parsing ASN.1 DER-encoded data such as
+ * that found in X.509 certificates. DER is a subset of BER/1, which has
+ * the advantage that it allows only a single encoding of primitive data.
+ * (High level data such as dates still support many encodings.) That is,
+ * it uses the "Definite" Encoding Rules (DER) not the "Basic" ones (BER).
+ *
+ * <P>
+ * Note that, like BER/1, DER streams are streams of explicitly tagged data values. Accordingly, this programming
+ * interface does not expose any variant of the java.io.InputStream interface, since that kind of input stream holds
+ * untagged data values and using that I/O model could prevent correct parsing of the DER data.
+ *
+ * <P>
+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is
+ * sufficient for parsing most X.509 certificates.
+ *
+ * @version 1.35
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class DerInputStream {
+ /*
+ * This version only supports fully buffered DER. This is easy to
+ * work with, though if large objects are manipulated DER becomes
+ * awkward to deal with. That's where BER is useful, since BER
+ * handles streaming data relatively well.
+ */
+ DerInputBuffer buffer;
+
+ /**
+ * Create a DER input stream from a data buffer. The buffer is not
+ * copied, it is shared. Accordingly, the buffer should be treated
+ * as read-only.
+ *
+ * @param data the buffer from which to create the string (CONSUMED)
+ */
+ public DerInputStream(byte[] data) {
+ buffer = new DerInputBuffer(data);
+ buffer.mark(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Create a DER input stream from part of a data buffer.
+ * The buffer is not copied, it is shared. Accordingly, the
+ * buffer should be treated as read-only.
+ *
+ * @param data the buffer from which to create the string (CONSUMED)
+ * @param offset the first index of <em>data</em> which will
+ * be read as DER input in the new stream
+ * @param len how long a chunk of the buffer to use,
+ * starting at "offset"
+ */
+ public DerInputStream(byte[] data, int offset, int len) {
+ buffer = new DerInputBuffer(data, offset, len);
+ buffer.mark(Integer.MAX_VALUE);
+ }
+
+ DerInputStream(DerInputBuffer buf) {
+ buffer = buf;
+ buffer.mark(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates a new DER input stream from part of this input stream.
+ *
+ * @param len how long a chunk of the current input stream to use,
+ * starting at the current position.
+ * @param do_skip true if the existing data in the input stream should
+ * be skipped. If this value is false, the next data read
+ * on this stream and the newly created stream will be the
+ * same.
+ */
+ public DerInputStream subStream(int len, boolean do_skip)
+ throws IOException {
+ DerInputBuffer newbuf = buffer.dup();
+
+ newbuf.truncate(len);
+ if (do_skip)
+ buffer.skip(len);
+ return new DerInputStream(newbuf);
+ }
+
+ /**
+ * Return what has been written to this DerInputStream
+ * as a byte array. Useful for debugging.
+ */
+ public byte[] toByteArray() {
+ return buffer.toByteArray();
+ }
+
+ /*
+ * PRIMITIVES -- these are "universal" ASN.1 simple types.
+ *
+ * INTEGER, BIT STRING, OCTET STRING, NULL
+ * OBJECT IDENTIFIER, SEQUENCE (OF), SET (OF)
+ * PrintableString, T61String, IA5String, UTCTime
+ */
+
+ /**
+ * Get an (unsigned) integer from the input stream.
+ */
+ public BigInt getInteger() throws IOException {
+ if (buffer.read() != DerValue.tag_Integer)
+ throw new IOException("DER input, Integer tag error");
+
+ return buffer.getUnsigned(getLength(buffer));
+ }
+
+ /**
+ * Get a bit string from the input stream. Only octet-aligned
+ * bitstrings (multiples of eight bits in length) are handled
+ * by this method.
+ */
+ public byte[] getBitString() throws IOException {
+ if (buffer.read() != DerValue.tag_BitString)
+ throw new IOException("DER input not an bit string");
+ int length = getLength(buffer);
+
+ /*
+ * This byte affects alignment and padding (for the last byte).
+ * Use getUnalignedBitString() for none 8-bit aligned bit strings.
+ */
+ if (buffer.read() != 0)
+ return null;
+ length--;
+
+ /*
+ * Just read the data into an aligned, padded octet buffer.
+ */
+ byte[] retval = new byte[length];
+ if (buffer.read(retval) != length)
+ throw new IOException("short read of DER bit string");
+ return retval;
+ }
+
+ /**
+ * Get a bit string from the input stream. The bit string need
+ * not be byte-aligned.
+ */
+ public BitArray getUnalignedBitString() throws IOException {
+ if (buffer.read() != DerValue.tag_BitString)
+ throw new IOException("DER input not a bit string");
+
+ int length = getLength(buffer) - 1;
+
+ /*
+ * First byte = number of excess bits in the last octet of the
+ * representation.
+ */
+ int validBits = length * 8 - buffer.read();
+
+ byte[] repn = new byte[length];
+
+ if (buffer.read(repn) != length)
+ throw new IOException("short read of DER bit string");
+ return new BitArray(validBits, repn);
+ }
+
+ /**
+ * Returns an ASN.1 OCTET STRING from the input stream.
+ */
+ public byte[] getOctetString() throws IOException {
+ if (buffer.read() != DerValue.tag_OctetString)
+ throw new IOException("DER input not an octet string");
+
+ int length = getLength(buffer);
+ byte[] retval = new byte[length];
+ if (buffer.read(retval) != length)
+ throw new IOException("short read of DER octet string");
+
+ return retval;
+ }
+
+ /**
+ * Returns the asked number of bytes from the input stream.
+ */
+ public void getBytes(byte[] val) throws IOException {
+ if (val.length != 0) {
+ if (buffer.read(val) != val.length) {
+ throw new IOException("short read of DER octet string");
+ }
+ }
+ }
+
+ /**
+ * Reads an encoded null value from the input stream.
+ */
+ public void getNull() throws IOException {
+ if (buffer.read() != DerValue.tag_Null || buffer.read() != 0)
+ throw new IOException("getNull, bad data");
+ }
+
+ /**
+ * Reads an X.200 style Object Identifier from the stream.
+ */
+ public ObjectIdentifier getOID() throws IOException {
+ return new ObjectIdentifier(this);
+ }
+
+ /**
+ * Return a sequence of encoded entities. ASN.1 sequences are
+ * ordered, and they are often used, like a "struct" in C or C++,
+ * to group data values. They may have optional or context
+ * specific values.
+ *
+ * @param startLen guess about how long the sequence will be
+ * (used to initialize an auto-growing data structure)
+ * @return array of the values in the sequence
+ */
+ public DerValue[] getSequence(int startLen) throws IOException {
+ int b = buffer.read();
+ if (b != DerValue.tag_Sequence)
+ throw new IOException("Sequence tag error " + b);
+ return readVector(startLen);
+ }
+
+ public void skipSequence(int startLen) throws IOException {
+ int b = buffer.read();
+ if (b != DerValue.tag_Sequence)
+ throw new IOException("Sequence tag error " + b);
+ int len = getLength(buffer);
+ buffer.skip(len);
+ }
+
+ /**
+ * Return a set of encoded entities. ASN.1 sets are unordered,
+ * though DER may specify an order for some kinds of sets (such
+ * as the attributes in an X.500 relative distinguished name)
+ * to facilitate binary comparisons of encoded values.
+ *
+ * @param startLen guess about how large the set will be
+ * (used to initialize an auto-growing data structure)
+ * @return array of the values in the sequence
+ */
+ public DerValue[] getSet(int startLen) throws IOException {
+ if (buffer.read() != DerValue.tag_Set)
+ throw new IOException("Set tag error");
+ return readVector(startLen);
+ }
+
+ /**
+ * Return a set of encoded entities. ASN.1 sets are unordered,
+ * though DER may specify an order for some kinds of sets (such
+ * as the attributes in an X.500 relative distinguished name)
+ * to facilitate binary comparisons of encoded values.
+ *
+ * @param startLen guess about how large the set will be
+ * (used to initialize an auto-growing data structure)
+ * @param implicit if true tag is assumed implicit.
+ * @return array of the values in the sequence
+ */
+ public DerValue[] getSet(int startLen, boolean implicit) throws IOException {
+ int tag = buffer.read();
+ if (!implicit) {
+ if (tag != DerValue.tag_Set) {
+ throw new IOException("Set tag error");
+ }
+ }
+ return (readVector(startLen));
+ }
+
+ /*
+ * Read a "vector" of values ... set or sequence have the
+ * same encoding, except for the initial tag, so both use
+ * this same helper routine.
+ */
+ protected DerValue[] readVector(int startLen) throws IOException {
+ int len = getLength(buffer);
+ DerInputStream newstr;
+
+ if (len == 0)
+ // return empty array instead of null, which should be
+ // used only for missing optionals
+ return new DerValue[0];
+
+ /*
+ * Create a temporary stream from which to read the data,
+ * unless it's not really needed.
+ */
+ if (buffer.available() == len)
+ newstr = this;
+ else
+ newstr = subStream(len, true);
+
+ /*
+ * Pull values out of the stream.
+ */
+ Vector<DerValue> vec = new Vector<DerValue>(startLen);
+ DerValue value;
+
+ do {
+ value = new DerValue(newstr.buffer);
+ vec.addElement(value);
+ } while (newstr.available() > 0);
+
+ if (newstr.available() != 0)
+ throw new IOException("extra data at end of vector");
+
+ /*
+ * Now stick them into the array we're returning.
+ */
+ int i, max = vec.size();
+ DerValue[] retval = new DerValue[max];
+
+ for (i = 0; i < max; i++)
+ retval[i] = (DerValue) vec.elementAt(i);
+
+ return retval;
+ }
+
+ /**
+ * Get a single DER-encoded value from the input stream.
+ * It can often be useful to pull a value from the stream
+ * and defer parsing it. For example, you can pull a nested
+ * sequence out with one call, and only examine its elements
+ * later when you really need to.
+ */
+ public DerValue getDerValue() throws IOException {
+ return new DerValue(buffer);
+ }
+
+ public String getPrintableString() throws IOException {
+ return (new DerValue(buffer)).getPrintableString();
+ }
+
+ public String getT61String() throws IOException {
+ return (new DerValue(buffer)).getT61String();
+ }
+
+ public String getIA5String() throws IOException {
+ return (new DerValue(buffer)).getIA5String();
+ }
+
+ public String getBMPString() throws IOException {
+ return (new DerValue(buffer)).getBMPString();
+ }
+
+ public String getUniversalString() throws IOException {
+ return (new DerValue(buffer)).getUniversalString();
+ }
+
+ /**
+ * Get a UTC encoded time value from the input stream.
+ */
+ public Date getUTCTime() throws IOException {
+ if (buffer.read() != DerValue.tag_UtcTime)
+ throw new IOException("DER input, UTCtime tag invalid ");
+ if (buffer.available() < 11)
+ throw new IOException("DER input, UTCtime short input");
+
+ int len = getLength(buffer);
+
+ if (len < 11 || len > 17)
+ throw new IOException("DER getUTCTime length error");
+
+ /*
+ * UTC time encoded as ASCII chars, YYMMDDhhmmss.
+ * If YY <= 50, we assume 20YY;
+ * if YY > 50, we assume 19YY, as per IETF-PKIX part I.
+ */
+ int year, month, day, hour, minute, second;
+
+ year = 10 * Character.digit((char) buffer.read(), 10);
+ year += Character.digit((char) buffer.read(), 10);
+ if (year <= 50) // origin 2000
+ year += 2000;
+ else
+ year += 1900; // origin 1900
+
+ month = 10 * Character.digit((char) buffer.read(), 10);
+ month += Character.digit((char) buffer.read(), 10);
+ month -= 1; // months are 0-11
+
+ day = 10 * Character.digit((char) buffer.read(), 10);
+ day += Character.digit((char) buffer.read(), 10);
+
+ hour = 10 * Character.digit((char) buffer.read(), 10);
+ hour += Character.digit((char) buffer.read(), 10);
+
+ minute = 10 * Character.digit((char) buffer.read(), 10);
+ minute += Character.digit((char) buffer.read(), 10);
+
+ len -= 10;
+
+ /**
+ * We allow for non-encoded seconds, even though the
+ * IETF-PKIX specification says that the seconds should
+ * always be encoded even if it is zero.
+ */
+
+ if (len == 3 || len == 7) {
+ second = 10 * Character.digit((char) buffer.read(), 10);
+ second += Character.digit((char) buffer.read(), 10);
+ len -= 2;
+ } else
+ second = 0;
+
+ if (month < 0 || day <= 0
+ || month > 11 || day > 31 || hour >= 24
+ || minute >= 60 || second >= 60)
+ throw new IOException("Parse UTC time, invalid format");
+
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.set(year, month, day, hour, minute, second);
+ cal.set(Calendar.MILLISECOND, 0); /* To clear millisecond field */
+ cal.set(Calendar.ERA, GregorianCalendar.AD);
+ Date readDate = cal.getTime();
+ long utcTime = readDate.getTime();
+
+ /*
+ * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm
+ */
+ if (!(len == 1 || len == 5))
+ throw new IOException("Parse UTC time, invalid offset");
+
+ switch (buffer.read()) {
+ case '+': {
+ int Htmp = 10 * Character.digit((char) buffer.read(), 10);
+ Htmp += Character.digit((char) buffer.read(), 10);
+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10);
+ Mtmp += Character.digit((char) buffer.read(), 10);
+
+ if (Htmp >= 24 || Mtmp >= 60)
+ throw new IOException("Parse UTCtime, +hhmm");
+
+ utcTime += ((Htmp * 60) + Mtmp) * 60 * 1000;
+ }
+ break;
+
+ case '-': {
+ int Htmp = 10 * Character.digit((char) buffer.read(), 10);
+ Htmp += Character.digit((char) buffer.read(), 10);
+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10);
+ Mtmp += Character.digit((char) buffer.read(), 10);
+
+ if (Htmp >= 24 || Mtmp >= 60)
+ throw new IOException("Parse UTCtime, -hhmm");
+
+ utcTime -= ((Htmp * 60) + Mtmp) * 60 * 1000;
+ }
+ break;
+
+ case 'Z':
+ break;
+
+ default:
+ throw new IOException("Parse UTCtime, garbage offset");
+ }
+ readDate.setTime(utcTime);
+ return readDate;
+ }
+
+ /**
+ * Get a Generalized encoded time value from the input stream.
+ */
+ public Date getGeneralizedTime() throws IOException {
+ if (buffer.read() != DerValue.tag_GeneralizedTime)
+ throw new IOException("DER input, GeneralizedTime tag invalid ");
+
+ if (buffer.available() < 13)
+ throw new IOException("DER input, GeneralizedTime short input");
+
+ int len = getLength(buffer);
+
+ /*
+ * Generalized time encoded as ASCII chars, YYYYMMDDhhmm[ss]
+ */
+ int year, month, day, hour, minute, second;
+
+ year = 1000 * Character.digit((char) buffer.read(), 10);
+ year += 100 * Character.digit((char) buffer.read(), 10);
+ year += 10 * Character.digit((char) buffer.read(), 10);
+ year += Character.digit((char) buffer.read(), 10);
+
+ month = 10 * Character.digit((char) buffer.read(), 10);
+ month += Character.digit((char) buffer.read(), 10);
+ month -= 1; // Calendar months are 0-11
+
+ day = 10 * Character.digit((char) buffer.read(), 10);
+ day += Character.digit((char) buffer.read(), 10);
+
+ hour = 10 * Character.digit((char) buffer.read(), 10);
+ hour += Character.digit((char) buffer.read(), 10);
+
+ minute = 10 * Character.digit((char) buffer.read(), 10);
+ minute += Character.digit((char) buffer.read(), 10);
+
+ len -= 12;
+
+ /**
+ * We allow for non-encoded seconds, even though the
+ * IETF-PKIX specification says that the seconds should
+ * always be encoded even if it is zero.
+ */
+
+ if (len == 3 || len == 7) {
+ second = 10 * Character.digit((char) buffer.read(), 10);
+ second += Character.digit((char) buffer.read(), 10);
+ len -= 2;
+ } else
+ second = 0;
+
+ if (month < 0 || day <= 0
+ || month > 11 || day > 31 || hour >= 24
+ || minute >= 60 || second >= 60)
+ throw new IOException("Parse Generalized time, invalid format");
+
+ /* Shouldn't this construct a Gregorian calendar directly???
+ * We don't really want locale dependant processing here */
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.set(year, month, day, hour, minute, second);
+ cal.set(Calendar.MILLISECOND, 0); /* To clear millisecond field */
+ cal.set(Calendar.ERA, GregorianCalendar.AD);
+ Date readDate = cal.getTime();
+ long utcTime = readDate.getTime();
+
+ /*
+ * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm
+ */
+ if (!(len == 1 || len == 5))
+ throw new IOException("Parse Generalized time, invalid offset");
+
+ switch (buffer.read()) {
+ case '+': {
+ int Htmp = 10 * Character.digit((char) buffer.read(), 10);
+ Htmp += Character.digit((char) buffer.read(), 10);
+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10);
+ Mtmp += Character.digit((char) buffer.read(), 10);
+
+ if (Htmp >= 24 || Mtmp >= 60)
+ throw new IOException("Parse GeneralizedTime, +hhmm");
+
+ utcTime += ((Htmp * 60) + Mtmp) * 60 * 1000;
+ }
+ break;
+
+ case '-': {
+ int Htmp = 10 * Character.digit((char) buffer.read(), 10);
+ Htmp += Character.digit((char) buffer.read(), 10);
+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10);
+ Mtmp += Character.digit((char) buffer.read(), 10);
+
+ if (Htmp >= 24 || Mtmp >= 60)
+ throw new IOException("Parse GeneralizedTime, -hhmm");
+
+ utcTime -= ((Htmp * 60) + Mtmp) * 60 * 1000;
+ }
+ break;
+
+ case 'Z':
+ break;
+
+ default:
+ throw new IOException("Parse GeneralizedTime, garbage offset");
+ }
+ readDate.setTime(utcTime);
+ return readDate;
+ }
+
+ /*
+ * Get a byte from the input stream.
+ */
+ // package private
+ int getByte() throws IOException {
+ return (0x00ff & buffer.read());
+ }
+
+ public int peekByte() throws IOException {
+ return buffer.peek();
+ }
+
+ // package private
+ int getLength() throws IOException {
+ return getLength(buffer);
+ }
+
+ /*
+ * Get a length from the input stream, allowing for at most 32 bits of
+ * encoding to be used. (Not the same as getting a tagged integer!)
+ */
+ static int getLength(InputStream in) throws IOException {
+ int value, tmp;
+
+ tmp = in.read();
+ if ((tmp & 0x080) == 0x00) { // 1 byte datum?
+ value = tmp;
+ } else { // no, more ...
+ tmp &= 0x07f;
+
+ /*
+ * NOTE: tmp == 0 indicates BER encoded data.
+ * tmp > 4 indicates more than 4Gb of data.
+ */
+ if (tmp <= 0 || tmp > 4)
+ throw new IOException("DerInput.getLength(): lengthTag="
+ + tmp + ", "
+ + ((tmp == 0) ? "Indefinite length encoding not supported"
+ + " or incorrect DER encoding."
+ : "too big."));
+
+ for (value = 0; tmp > 0; tmp--) {
+ value <<= 8;
+ value += 0x0ff & in.read();
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Mark the current position in the buffer, so that
+ * a later call to <code>reset</code> will return here.
+ */
+ public void mark(int value) {
+ buffer.mark(value);
+ }
+
+ /**
+ * Return to the position of the last <code>mark</code> call. A mark is implicitly set at the beginning of
+ * the stream when it is created.
+ */
+ public void reset() {
+ buffer.reset();
+ }
+
+ /**
+ * Returns the number of bytes available for reading.
+ * This is most useful for testing whether the stream is
+ * empty.
+ */
+ public int available() {
+ return buffer.available();
+ }
+}
diff --git a/base/util/src/netscape/security/util/DerOutputStream.java b/base/util/src/netscape/security/util/DerOutputStream.java
new file mode 100644
index 000000000..62290d604
--- /dev/null
+++ b/base/util/src/netscape/security/util/DerOutputStream.java
@@ -0,0 +1,729 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * Output stream marshaling DER-encoded data. This is eventually provided
+ * in the form of a byte array; there is no advance limit on the size of
+ * that byte array.
+ *
+ * <P>
+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is
+ * sufficient for generating most X.509 certificates.
+ *
+ * @version 1.32
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class DerOutputStream
+ extends ByteArrayOutputStream implements DerEncoder {
+ /**
+ * Construct an DER output stream.
+ *
+ * @param size how large a buffer to preallocate.
+ */
+ public DerOutputStream(int size) {
+ super(size);
+ }
+
+ /**
+ * Construct an DER output stream.
+ */
+ public DerOutputStream() {
+ }
+
+ /**
+ * Writes tagged, pre-marshaled data. This calcuates and encodes
+ * the length, so that the output data is the standard triple of
+ * { tag, length, data } used by all DER values.
+ *
+ * @param tag the DER value tag for the data, such as <em>DerValue.tag_Sequence</em>
+ * @param buf buffered data, which must be DER-encoded
+ */
+ public void write(byte tag, byte[] buf) throws IOException {
+ write(tag);
+ putLength(buf.length);
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * Writes tagged data using buffer-to-buffer copy. As above,
+ * this writes a standard DER record. This is often used when
+ * efficiently encapsulating values in sequences.
+ *
+ * @param tag the DER value tag for the data, such as <em>DerValue.tag_Sequence</em>
+ * @param out buffered data
+ */
+ public void write(byte tag, DerOutputStream out) throws IOException {
+ write(tag);
+ putLength(out.count);
+ write(out.buf, 0, out.count);
+ }
+
+ /**
+ * Writes implicitly tagged data using buffer-to-buffer copy. As above,
+ * this writes a standard DER record. This is often used when
+ * efficiently encapsulating implicitly tagged values.
+ *
+ * @param tag the DER value of the context-specific tag that replaces
+ * original tag of the value in the output , such as in
+ *
+ * <pre>
+ * <em> <field> [N] IMPLICIT <type></em>
+ * </pre>
+ *
+ * For example, <em>FooLength [1] IMPLICIT INTEGER</em>, with value=4;
+ * would be encoded as "81 01 04" whereas in explicit
+ * tagging it would be encoded as "A1 03 02 01 04".
+ * Notice that the tag is A1 and not 81, this is because with
+ * explicit tagging the form is always constructed.
+ * @param value original value being implicitly tagged
+ */
+ public void writeImplicit(byte tag, DerOutputStream value)
+ throws IOException {
+ write(tag);
+ write(value.buf, 1, value.count - 1);
+ }
+
+ /**
+ * Marshals pre-encoded DER value onto the output stream.
+ */
+ public void putDerValue(DerValue val) throws IOException {
+ val.encode(this);
+ }
+
+ /*
+ * PRIMITIVES -- these are "universal" ASN.1 simple types.
+ *
+ * BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL
+ * OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF)
+ * PrintableString, T61String, IA5String, UTCTime
+ */
+
+ /**
+ * Marshals a DER boolean on the output stream.
+ */
+ public void putBoolean(boolean val) throws IOException {
+ write(DerValue.tag_Boolean);
+ putLength(1);
+ if (val) {
+ write(0xff);
+ } else {
+ write(0);
+ }
+ }
+
+ /**
+ * Marshals a DER unsigned integer on the output stream.
+ */
+ public void putInteger(BigInt i) throws IOException {
+ putUnsignedInteger(i.toByteArray());
+ }
+
+ /**
+ * Marshals a DER unsigned integer on the output stream.
+ */
+ public void putUnsignedInteger(byte[] integerBytes) throws IOException {
+
+ write(DerValue.tag_Integer);
+ if ((integerBytes[0] & 0x080) != 0) {
+ /*
+ * prepend zero so it's not read as a negative number
+ */
+ putLength(integerBytes.length + 1);
+ write(0);
+ } else
+ putLength(integerBytes.length);
+ write(integerBytes, 0, integerBytes.length);
+ }
+
+ /**
+ * Marshals a DER enumerated value on the output stream.
+ */
+ public void putEnumerated(int i) throws IOException {
+ write(DerValue.tag_Enumerated);
+
+ int bytemask = 0xff000000;
+ int signmask = 0x80000000;
+ int length;
+ if ((i & 0x80000000) != 0) {
+ // negative case
+ for (length = 4; length > 1; --length) {
+ if ((i & bytemask) != bytemask)
+ break;
+ bytemask = bytemask >>> 8;
+ signmask = signmask >>> 8;
+ }
+ if ((i & signmask) == 0) {
+ // ensure negative case
+ putLength(length + 1);
+ write(0xff);
+ } else {
+ putLength(length);
+ }
+ // unrolled loop
+ switch (length) {
+ case 4:
+ write((byte) (i >>> 24));
+ case 3:
+ write((byte) (i >>> 16));
+ case 2:
+ write((byte) (i >>> 8));
+ case 1:
+ write((byte) i);
+ }
+ } else {
+ // positive case
+ for (length = 4; length > 0; --length) {
+ if ((i & bytemask) != 0)
+ break;
+ bytemask = bytemask >>> 8;
+ signmask = signmask >>> 8;
+ }
+ if ((i & signmask) != 0) {
+ // ensure posititive case
+ putLength(length + 1);
+ write(0x00);
+ } else {
+ putLength(length);
+ }
+ // unrolled loop
+ switch (length) {
+ case 4:
+ write((byte) (i >>> 24));
+ case 3:
+ write((byte) (i >>> 16));
+ case 2:
+ write((byte) (i >>> 8));
+ case 1:
+ write((byte) i);
+ }
+ }
+ }
+
+ /**
+ * Marshals a DER bit string on the output stream. The bit
+ * string must be byte-aligned.
+ *
+ * @param bits the bit string, MSB first
+ */
+ public void putBitString(byte[] bits) throws IOException {
+ write(DerValue.tag_BitString);
+ putLength(bits.length + 1);
+ write(0); // all of last octet is used
+ write(bits);
+ }
+
+ /**
+ * Converts a boolean array to a BitArray. Trims trailing 0 bits
+ * in accordance with DER encoding standard. We assume the input is not
+ * null.
+ */
+ private static BitArray toBitArray(boolean[] bitString) {
+ if (bitString.length == 0) {
+ return new BitArray(bitString);
+ }
+
+ // find index of last 1 bit. -1 if there aren't any
+ int i;
+ for (i = bitString.length - 1; i >= 0; i--) {
+ if (bitString[i]) {
+ break;
+ }
+ }
+ int length = i + 1;
+
+ // if length changed, copy to new appropriately-sized array
+ if (length != bitString.length) {
+ boolean[] newBitString = new boolean[length];
+ System.arraycopy(bitString, 0, newBitString, 0, length);
+ bitString = newBitString;
+ }
+
+ return new BitArray(bitString);
+ }
+
+ /**
+ * Converts bit string to a BitArray, stripping off trailing 0 bits.
+ * We assume that the bit string is not null.
+ */
+ private static BitArray toBitArray(byte[] bitString) {
+ // compute length in bits of bit string
+ int length, i;
+ int maxIndex = 0;
+
+ if (bitString.length == 0) {
+ return new BitArray(0, bitString);
+ }
+
+ // find the index of the last byte with a 1 bit
+ for (i = 0; i < bitString.length; i++) {
+ if (bitString[i] != 0) {
+ maxIndex = i;
+ }
+ }
+ byte lastByte = bitString[maxIndex];
+ length = (maxIndex + 1) * 8; // maximum, might reduce in next step
+
+ // now find the last 1 bit in this last byte
+ for (i = 1; i <= 0x80; i <<= 1) {
+ if ((lastByte & i) == 0) {
+ length--;
+ } else {
+ break;
+ }
+ }
+ return new BitArray(length, bitString);
+ }
+
+ /**
+ * Marshals a DER bit string on the output stream.
+ * The bit strings need not be byte-aligned.
+ *
+ * @param bits the bit string, MSB first
+ */
+ public void putUnalignedBitString(BitArray ba) throws IOException {
+ byte[] bits = ba.toByteArray();
+
+ write(DerValue.tag_BitString);
+ putLength(bits.length + 1);
+ write(bits.length * 8 - ba.length()); // excess bits in last octet
+ write(bits);
+ }
+
+ /**
+ * Marshals a DER bit string on the output stream.
+ * All trailing 0 bits will be stripped off in accordance with DER
+ * encoding.
+ *
+ * @param bits the bit string, MSB first
+ */
+ public void putUnalignedBitString(byte[] bitString) throws IOException {
+ putUnalignedBitString(toBitArray(bitString));
+ }
+
+ /**
+ * Marshals a DER bit string on the output stream.
+ * All trailing 0 bits will be stripped off in accordance with DER
+ * encoding.
+ *
+ * @param bits the bit string as an array of booleans.
+ */
+ public void putUnalignedBitString(boolean[] bitString) throws IOException {
+ putUnalignedBitString(toBitArray(bitString));
+ }
+
+ /**
+ * DER-encodes an ASN.1 OCTET STRING value on the output stream.
+ *
+ * @param octets the octet string
+ */
+ public void putOctetString(byte[] octets) throws IOException {
+ write(DerValue.tag_OctetString, octets);
+ }
+
+ /**
+ * Marshals a DER "null" value on the output stream. These are
+ * often used to indicate optional values which have been omitted.
+ */
+ public void putNull() throws IOException {
+ write(DerValue.tag_Null);
+ putLength(0);
+ }
+
+ /**
+ * Marshals an object identifier (OID) on the output stream.
+ * Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct.
+ */
+ public void putOID(ObjectIdentifier oid) throws IOException {
+ oid.encode(this);
+ }
+
+ /**
+ * Marshals a sequence on the output stream. This supports both
+ * the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF"
+ * (one to N values) constructs.
+ */
+ public void putSequence(DerValue[] seq) throws IOException {
+ DerOutputStream bytes = new DerOutputStream();
+ int i;
+
+ for (i = 0; i < seq.length; i++)
+ seq[i].encode(bytes);
+
+ write(DerValue.tag_Sequence, bytes);
+ }
+
+ /**
+ * Marshals the contents of a set on the output stream without
+ * ordering the elements. Ok for BER encoding, but not for DER
+ * encoding.
+ *
+ * For DER encoding, use orderedPutSet() or orderedPutSetOf().
+ */
+ public void putSet(DerValue[] set) throws IOException {
+ DerOutputStream bytes = new DerOutputStream();
+ int i;
+
+ for (i = 0; i < set.length; i++)
+ set[i].encode(bytes);
+
+ write(DerValue.tag_Set, bytes);
+ }
+
+ /**
+ * NSCP :
+ * Like putOrderSetOf, except not sorted.
+ * This may defy DER encoding but is needed for compatibility
+ * with communicator.
+ */
+ public void putSet(byte tag, DerEncoder[] set) throws IOException {
+ putOrderedSet(tag, set, null);
+ }
+
+ /**
+ * Marshals the contents of a set on the output stream. Sets
+ * are semantically unordered, but DER requires that encodings of
+ * set elements be sorted into ascending lexicographical order
+ * before being output. Hence sets with the same tags and
+ * elements have the same DER encoding.
+ *
+ * This method supports the ASN.1 "SET OF" construct, but not
+ * "SET", which uses a different order.
+ */
+ public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException {
+ putOrderedSet(tag, set, lexOrder);
+ }
+
+ /**
+ * Marshals the contents of a set on the output stream. Sets
+ * are semantically unordered, but DER requires that encodings of
+ * set elements be sorted into ascending tag order
+ * before being output. Hence sets with the same tags and
+ * elements have the same DER encoding.
+ *
+ * This method supports the ASN.1 "SET" construct, but not
+ * "SET OF", which uses a different order.
+ */
+ public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException {
+ putOrderedSet(tag, set, tagOrder);
+ }
+
+ /**
+ * Lexicographical order comparison on byte arrays, for ordering
+ * elements of a SET OF objects in DER encoding.
+ */
+ private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder();
+
+ /**
+ * Tag order comparison on byte arrays, for ordering elements of
+ * SET objects in DER encoding.
+ */
+ private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder();
+
+ /**
+ * Marshals a the contents of a set on the output stream with the
+ * encodings of its sorted in increasing order.
+ *
+ * @param order the order to use when sorting encodings of components.
+ */
+ private void putOrderedSet(byte tag, DerEncoder[] set,
+ Comparator<byte[]> order) throws IOException {
+ DerOutputStream[] streams = new DerOutputStream[set.length];
+
+ for (int i = 0; i < set.length; i++) {
+ streams[i] = new DerOutputStream();
+ set[i].derEncode(streams[i]);
+ }
+
+ // order the element encodings
+ byte[][] bufs = new byte[streams.length][];
+ for (int i = 0; i < streams.length; i++) {
+ bufs[i] = streams[i].toByteArray();
+ }
+ if (order != null) {
+ Arrays.sort(bufs, order);
+ }
+
+ DerOutputStream bytes = new DerOutputStream();
+ for (int i = 0; i < streams.length; i++) {
+ bytes.write(bufs[i]);
+ }
+ write(tag, bytes);
+
+ }
+
+ /**
+ * Converts string to printable and writes to der output stream.
+ */
+ public void putPrintableString(String s) throws IOException {
+ putStringType(DerValue.tag_PrintableString, s);
+ }
+
+ public void putVisibleString(String s) throws IOException {
+ putStringType(DerValue.tag_VisibleString, s);
+ }
+
+ /**
+ * Marshals a string which is consists of BMP (unicode) characters
+ */
+ public void putBMPString(String s) throws IOException {
+ putStringType(DerValue.tag_BMPString, s);
+ }
+
+ public void putGeneralString(String s) throws IOException {
+ putStringType(DerValue.tag_GeneralString, s);
+ }
+
+ // /*
+ // * T61 is an 8 bit extension to ASCII, escapes e.g. to Japanese
+ // */
+ // void putT61String(String s) throws IOException
+ // {
+ // // XXX IMPLEMENT ME
+ //
+ // throw new IOException("DerOutputStream.putT61String() NYI");
+ // }
+
+ // /*
+ // * Universal String.
+ // */
+ // void putUniversalString(String s) throws IOException
+ // {
+ // // XXX IMPLEMENT ME
+ //
+ // throw new IOException("DerOutputStream.putUniversalString() NYI");
+ // }
+
+ /**
+ * Marshals a string which is consists of IA5(ASCII) characters
+ */
+ public void putIA5String(String s) throws IOException {
+ putStringType(DerValue.tag_IA5String, s);
+ }
+
+ public void putUTF8String(String s) throws IOException {
+ putStringType(DerValue.tag_UTF8String, s);
+ }
+
+ public void putStringType(byte tag, String s) throws IOException {
+ try {
+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tag);
+ if (encoder == null)
+ throw new IOException("No encoder for tag");
+
+ CharBuffer charBuffer = CharBuffer.wrap(s.toCharArray());
+ ByteBuffer byteBuffer = encoder.encode(charBuffer);
+
+ write(tag);
+ putLength(byteBuffer.limit());
+ write(byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit());
+
+ } catch (CharacterCodingException e) {
+ throw new IOException("Not a valid string type " + tag, e);
+ }
+ }
+
+ private void put2DateBytes(byte[] buffer, int value, int offset) {
+ int upper = value / 10;
+ int lower = value % 10;
+ buffer[offset] = (byte) ((byte) upper + (byte) '0');
+ buffer[offset + 1] = (byte) ((byte) lower + (byte) '0');
+ }
+
+ private static Calendar GMTGregorianCalendar = null;
+
+ private Calendar getGMTGregorianCalendar() {
+ if (GMTGregorianCalendar == null) {
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ GMTGregorianCalendar = new GregorianCalendar(tz);
+ }
+ return (Calendar) GMTGregorianCalendar.clone();
+ }
+
+ public byte[] getDateBytes(Date d, boolean UTC) {
+
+ byte[] datebytes;
+
+ if (UTC) {
+ datebytes = new byte[13];
+ } else { // generalized time has 4 digits for yr
+ datebytes = new byte[15];
+ }
+
+ Calendar cal = getGMTGregorianCalendar();
+ cal.setTime(d);
+
+ int i = 0;
+ if (!UTC) {
+ put2DateBytes(datebytes, cal.get(Calendar.YEAR) / 100, i);
+ i += 2;
+ }
+ put2DateBytes(datebytes, cal.get(Calendar.YEAR) % 100, i);
+ // Calendar's MONTH is zero-based
+ i += 2;
+ put2DateBytes(datebytes, cal.get(Calendar.MONTH) + 1, i);
+ i += 2;
+ put2DateBytes(datebytes, cal.get(Calendar.DAY_OF_MONTH), i);
+ i += 2;
+ put2DateBytes(datebytes, cal.get(Calendar.HOUR_OF_DAY), i);
+ i += 2;
+ put2DateBytes(datebytes, cal.get(Calendar.MINUTE), i);
+ i += 2;
+ put2DateBytes(datebytes, cal.get(Calendar.SECOND), i);
+ i += 2;
+ // datebytes[i] = 'Z';
+ datebytes[i] = (byte) 'Z';
+
+ return datebytes;
+ }
+
+ /**
+ * Marshals a DER UTC time/date value.
+ *
+ * <P>
+ * YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time and with seconds (even if seconds=0) as per IETF-PKIX
+ * partI.
+ */
+ public void putUTCTime(Date d) throws IOException {
+ /*
+ * Format the date.
+ */
+
+ // This was the old code. Way too slow to be usable (stevep)
+
+ // String pattern = "yyMMddHHmmss'Z'";
+ // SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ // TimeZone tz = TimeZone.getTimeZone("GMT");
+ // sdf.setTimeZone(tz);
+ // byte[] utc = (sdf.format(d)).getBytes();
+
+ byte[] datebytes = getDateBytes(d, true); // UTC = true
+
+ /*
+ * Write the formatted date.
+ */
+ write(DerValue.tag_UtcTime);
+ putLength(datebytes.length);
+ write(datebytes);
+ }
+
+ /**
+ * Marshals a DER Generalized Time/date value.
+ *
+ * <P>
+ * YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time and with seconds (even if seconds=0) as per
+ * IETF-PKIX partI.
+ */
+ public void putGeneralizedTime(Date d) throws IOException {
+ /*
+ * Format the date.
+ */
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+
+ // This is way too slow to be usable (stevep)
+ String pattern = "yyyyMMddHHmmss'Z'";
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ sdf.setTimeZone(tz);
+ byte[] gt = (sdf.format(d)).getBytes();
+
+ /*
+ * Write the formatted date.
+ */
+ write(DerValue.tag_GeneralizedTime);
+ putLength(gt.length);
+ write(gt);
+ }
+
+ /**
+ * Put the encoding of the length in the stream.
+ *
+ * @param len the length of the attribute.
+ * @exception IOException on writing errors.
+ */
+ public void putLength(int len) throws IOException {
+ if (len < 128) {
+ write((byte) len);
+
+ } else if (len < (1 << 8)) {
+ write((byte) 0x081);
+ write((byte) len);
+
+ } else if (len < (1 << 16)) {
+ write((byte) 0x082);
+ write((byte) (len >> 8));
+ write((byte) len);
+
+ } else if (len < (1 << 24)) {
+ write((byte) 0x083);
+ write((byte) (len >> 16));
+ write((byte) (len >> 8));
+ write((byte) len);
+
+ } else {
+ write((byte) 0x084);
+ write((byte) (len >> 24));
+ write((byte) (len >> 16));
+ write((byte) (len >> 8));
+ write((byte) len);
+ }
+ }
+
+ /**
+ * Put the tag of the attribute in the stream.
+ *
+ * @param class the tag class type, one of UNIVERSAL, CONTEXT,
+ * APPLICATION or PRIVATE
+ * @param form if true, the value is constructed, otherwise it is
+ * primitive.
+ * @param val the tag value
+ */
+ public void putTag(byte tagClass, boolean form, byte val) {
+ byte tag = (byte) (tagClass | val);
+ if (form) {
+ tag |= (byte) 0x20;
+ }
+ write(tag);
+ }
+
+ /**
+ * Write the current contents of this <code>DerOutputStream</code> to an <code>OutputStream</code>.
+ *
+ * @exception IOException on output error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ out.write(toByteArray());
+ }
+}
diff --git a/base/util/src/netscape/security/util/DerValue.java b/base/util/src/netscape/security/util/DerValue.java
new file mode 100644
index 000000000..71b6f7f2c
--- /dev/null
+++ b/base/util/src/netscape/security/util/DerValue.java
@@ -0,0 +1,715 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.util.Arrays;
+
+import netscape.security.x509.AVAValueConverter;
+import netscape.security.x509.GenericValueConverter;
+
+/**
+ * Represents a single DER-encoded value. DER encoding rules are a subset
+ * of the "Basic" Encoding Rules (BER), but they only support a single way
+ * ("Definite" encoding) to encode any given value.
+ *
+ * <P>
+ * All DER-encoded data are triples <em>{type, length, data}</em>. This class represents such tagged values as they have
+ * been read (or constructed), and provides structured access to the encoded data.
+ *
+ * <P>
+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is
+ * sufficient for parsing most X.509 certificates, and working with selected additional formats (such as PKCS #10
+ * certificate requests, and some kinds of PKCS #7 data).
+ *
+ * @version 1.43
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class DerValue {
+ /** The tag class types */
+ public static final byte TAG_UNIVERSAL = (byte) 0x000;
+ public static final byte TAG_APPLICATION = (byte) 0x040;
+ public static final byte TAG_CONTEXT = (byte) 0x080;
+ public static final byte TAG_PRIVATE = (byte) 0x0c0;
+
+ /** The DER tag of the value; one of the tag_ constants. */
+ public byte tag;
+
+ protected DerInputBuffer buffer;
+
+ /**
+ * The DER-encoded data of the value.
+ */
+ public DerInputStream data;
+
+ private int length;
+
+ /*
+ * The type starts at the first byte of the encoding, and
+ * is one of these tag_* values. That may be all the type
+ * data that is needed.
+ */
+
+ /*
+ * These tags are the "universal" tags ... they mean the same
+ * in all contexts. (Mask with 0x1f -- five bits.)
+ */
+
+ /** Tag value indicating an ASN.1 "BOOLEAN" value. */
+ public final static byte tag_Boolean = 0x01;
+
+ /** Tag value indicating an ASN.1 "INTEGER" value. */
+ public final static byte tag_Integer = 0x02;
+
+ /** Tag value indicating an ASN.1 "BIT STRING" value. */
+ public final static byte tag_BitString = 0x03;
+
+ /** Tag value indicating an ASN.1 "OCTET STRING" value. */
+ public final static byte tag_OctetString = 0x04;
+
+ /** Tag value indicating an ASN.1 "NULL" value. */
+ public final static byte tag_Null = 0x05;
+
+ /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */
+ public final static byte tag_ObjectId = 0x06;
+
+ /** Tag value including an ASN.1 "ENUMERATED" value */
+ public final static byte tag_Enumerated = 0x0A;
+
+ /** Tag value including a "printable" string */
+ public final static byte tag_PrintableString = 0x13;
+
+ public final static byte tag_VisibleString = 0x1A;
+
+ /** Tag value including a "teletype" string */
+ public final static byte tag_T61String = 0x14;
+
+ /** Tag value including an ASCII string */
+ public final static byte tag_IA5String = 0x16;
+
+ /** Tag value indicating an ASN.1 "UTCTime" value. */
+ public final static byte tag_UtcTime = 0x17;
+
+ /** Tag value indicating an ASN.1 "GeneralizedTime" value. */
+ public final static byte tag_GeneralizedTime = 0x18;
+
+ /** Tag value indicating an ASN.1 "GeneralString" value. */
+ public final static byte tag_GeneralString = 0x1B;
+
+ /** Tag value indicating an ASN.1 "BMPString" value. */
+ public final static byte tag_BMPString = 0x1E;
+
+ /** Tag value indicating an ASN.1 "UniversalString" value. */
+ public final static byte tag_UniversalString = 0x1C;
+
+ /** Tag value indicating an ASN.1 "UTF8String" value. (since 1998) */
+ public final static byte tag_UTF8String = 0x0C;
+
+ // CONSTRUCTED seq/set
+
+ /**
+ * Tag value indicating an ASN.1
+ * "SEQUENCE" (zero to N elements, order is significant).
+ */
+ public final static byte tag_Sequence = 0x30;
+
+ /**
+ * Tag value indicating an ASN.1
+ * "SEQUENCE OF" (one to N elements, order is significant).
+ */
+ public final static byte tag_SequenceOf = 0x30;
+
+ /**
+ * Tag value indicating an ASN.1
+ * "SET" (zero to N members, order does not matter).
+ */
+ public final static byte tag_Set = 0x31;
+
+ /**
+ * Tag value indicating an ASN.1
+ * "SET OF" (one to N members, order does not matter).
+ */
+ public final static byte tag_SetOf = 0x31;
+
+ /*
+ * These values are the high order bits for the other kinds of tags.
+ */
+ boolean isUniversal() {
+ return ((tag & 0x0c0) == 0x000);
+ }
+
+ boolean isApplication() {
+ return ((tag & 0x0c0) == 0x040);
+ }
+
+ /**
+ * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag.
+ * This is associated with the ASN.1 "DEFINED BY" syntax.
+ */
+ public boolean isContextSpecific() {
+ return ((tag & 0x0c0) == 0x080);
+ }
+
+ /**
+ * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag.
+ */
+ public boolean isContextSpecific(byte cntxtTag) {
+ if (!isContextSpecific()) {
+ return false;
+ }
+ return ((tag & 0x01f) == cntxtTag);
+ }
+
+ boolean isPrivate() {
+ return ((tag & 0x0c0) == 0x0c0);
+ }
+
+ /** Returns true iff the CONSTRUCTED bit is set in the type tag. */
+ public boolean isConstructed() {
+ return ((tag & 0x020) == 0x020);
+ }
+
+ /**
+ * Creates a DER value from a string
+ * using a generic way of determining the proper tag for the string.
+ * Assumes the string is a Generic attribute value and uses
+ * the converter for generic string values to convert to the Der Value.
+ */
+ public DerValue(String value)
+ throws IOException {
+ AVAValueConverter genericValue = new GenericValueConverter();
+ DerValue val;
+
+ val = genericValue.getValue(value);
+ tag = val.tag;
+ buffer = val.buffer;
+ length = val.length;
+ data = val.data;
+ data.mark(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates a DerValue from a tag and some DER-encoded data.
+ *
+ * @param tag the DER type tag
+ * @param data the DER-encoded data
+ */
+ public DerValue(byte tag, byte[] data) {
+ this.tag = tag;
+ buffer = new DerInputBuffer(data.clone());
+ length = data.length;
+ this.data = new DerInputStream(buffer);
+ this.data.mark(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates a DerValue from a tag and some DER-encoded data.
+ *
+ * @param tag the DER type tag
+ * @param data the DER-encoded data
+ * @param offset offset of the data
+ * @param length length of the data
+ */
+ public DerValue(byte tag, byte[] data, int offset, int length) {
+ this(tag, Arrays.copyOfRange(data, offset, offset + length));
+ }
+
+ /*
+ * package private
+ */
+ DerValue(DerInputBuffer in) throws IOException {
+ // NOTE: This must handle the special value used
+ // to terminate BER indefinite encodings (tag and
+ // length are both zero)
+
+ // XXX must also parse BER-encoded constructed
+ // values such as sequences, sets...
+
+ tag = (byte) in.read();
+ length = DerInputStream.getLength(in);
+
+ buffer = in.dup();
+ buffer.truncate(length);
+ data = new DerInputStream(buffer);
+
+ in.skip(length);
+ }
+
+ /**
+ * Get an ASN.1/DER encoded datum from a buffer. The
+ * entire buffer must hold exactly one datum, including
+ * its tag and length.
+ *
+ * @param buf buffer holding a single DER-encoded datum.
+ */
+ public DerValue(byte[] buf) throws IOException {
+ init(true, new ByteArrayInputStream(buf));
+ }
+
+ /**
+ * Get an ASN.1/DER encoded datum from part of a buffer.
+ * That part of the buffer must hold exactly one datum, including
+ * its tag and length.
+ *
+ * @param buf the buffer
+ * @param offset start point of the single DER-encoded dataum
+ * @param length how many bytes are in the encoded datum
+ */
+ public DerValue(byte[] buf, int offset, int len) throws IOException {
+ init(true, new ByteArrayInputStream(buf, offset, len));
+ }
+
+ /**
+ * Get an ASN1/DER encoded datum from an input stream. The
+ * stream may have additional data following the encoded datum.
+ *
+ * @param in the input stream holding a single DER datum,
+ * which may be followed by additional data
+ */
+ public DerValue(InputStream in) throws IOException {
+ init(false, in);
+ }
+
+ /*
+ * helper routine
+ */
+ private void init(boolean fullyBuffered, InputStream in)
+ throws IOException {
+ byte[] bytes;
+
+ tag = (byte) in.read();
+ length = DerInputStream.getLength(in);
+
+ /*
+ if (length == 0)
+ return;
+ */
+
+ if (fullyBuffered && in.available() != length)
+ throw new IOException("extra DER value data (constructor)");
+
+ bytes = new byte[length];
+
+ // n.b. readFully not needed in normal fullyBuffered case
+ DataInputStream dis = new DataInputStream(in);
+
+ dis.readFully(bytes);
+ buffer = new DerInputBuffer(bytes);
+ data = new DerInputStream(buffer);
+ }
+
+ /**
+ * Encode an ASN1/DER encoded datum onto a DER output stream.
+ */
+ public void encode(DerOutputStream out)
+ throws IOException {
+ out.write(tag);
+ out.putLength(length);
+ buffer.dump(out, length);
+
+ }
+
+ /**
+ * Returns an ASN.1 BOOLEAN
+ *
+ * @return the boolean held in this DER value
+ */
+ public boolean getBoolean() throws IOException {
+ if (tag != tag_Boolean) {
+ throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag);
+ }
+ if (length != 1) {
+ throw new IOException("DerValue.getBoolean, invalid length " + length);
+ }
+ if (buffer.read() != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns an ASN.1 OBJECT IDENTIFIER.
+ *
+ * @return the OID held in this DER value
+ */
+ public ObjectIdentifier getOID() throws IOException {
+ if (tag != tag_ObjectId)
+ throw new IOException("DerValue.getOID, not an OID " + tag);
+ return new ObjectIdentifier(buffer);
+ }
+
+ /**
+ * Returns an ASN.1 OCTET STRING
+ *
+ * @return the octet string held in this DER value
+ */
+ public byte[] getOctetString() throws IOException {
+ if (tag != tag_OctetString)
+ throw new IOException(
+ "DerValue.getOctetString, not an Octet String: " + tag);
+
+ byte[] bytes = new byte[length];
+
+ if (buffer.read(bytes) != length)
+ throw new IOException("short read on DerValue buffer");
+ return bytes;
+ }
+
+ /**
+ * Returns an ASN.1 unsigned integer value of enumerated value.
+ *
+ * @return the (unsigned) integer held in this DER value
+ */
+ public int getEnumerated()
+ throws IOException {
+ if (tag != tag_Enumerated)
+ throw new IOException("DerValue.getEnumerated, not an ENUMERATED " + tag);
+ if (length == 0)
+ return 0;
+ if (length > 4 || length < 1)
+ throw new IOException("DerValue.getEnumerated, invalid length " + length + "(must be between 1 and 4)");
+
+ int value = 0;
+ int nextbyte = buffer.read();
+ if (nextbyte == -1)
+ throw new IOException("short read on DerValue buffer");
+ // perform sign extension
+ value = (byte) nextbyte;
+
+ for (int i = length - 1; i > 0; --i) {
+ nextbyte = buffer.read();
+ if (nextbyte == -1)
+ throw new IOException("short read on DerValue buffer");
+ value = 256 * value + nextbyte;
+ }
+ return value;
+ }
+
+ /**
+ * Returns an ASN.1 unsigned INTEGER value.
+ *
+ * @return the (unsigned) integer held in this DER value
+ */
+ public BigInt getInteger() throws IOException {
+ if (tag != tag_Integer)
+ throw new IOException("DerValue.getInteger, not an int " + tag);
+ return buffer.getUnsigned(data.available());
+ }
+
+ /**
+ * Returns an ASN.1 unsigned INTEGER value, the parameter determining
+ * if the tag is implicit.
+ *
+ * @param tagImplicit if true, ignores the tag value as it is
+ * assumed implicit.
+ * @return the (unsigned) integer held in this DER value
+ */
+ public BigInt getInteger(boolean tagImplicit) throws IOException {
+ if (!tagImplicit) {
+ if (tag != tag_Integer) {
+ throw new IOException("DerValue.getInteger, not an int "
+ + tag);
+ }
+ }
+ return buffer.getUnsigned(data.available());
+ }
+
+ /**
+ * Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned.
+ *
+ * @return the bit string held in this value
+ */
+ public byte[] getBitString() throws IOException {
+ if (tag != tag_BitString)
+ throw new IOException(
+ "DerValue.getBitString, not a bit string " + tag);
+
+ return buffer.getBitString();
+ }
+
+ /**
+ * Returns an ASN.1 BIT STRING value that need not be byte-aligned.
+ *
+ * @return a BitArray representing the bit string held in this value
+ */
+ public BitArray getUnalignedBitString() throws IOException {
+ if (tag != tag_BitString)
+ throw new IOException(
+ "DerValue.getBitString, not a bit string " + tag);
+
+ return buffer.getUnalignedBitString();
+ }
+
+ /**
+ * Returns the name component as a Java string, regardless of its
+ * encoding restrictions (ASCII, T61, Printable, etc).
+ */
+ public String getAsString() throws IOException {
+ AVAValueConverter genericValue = new GenericValueConverter();
+ return genericValue.getAsString(this);
+ }
+
+ /**
+ * Returns an ASN.1 BIT STRING value, with the tag assumed implicit
+ * based on the parameter. The bit string must be byte-aligned.
+ *
+ * @param tagImplicit if true, the tag is assumed implicit.
+ * @return the bit string held in this value
+ */
+ public byte[] getBitString(boolean tagImplicit) throws IOException {
+ if (!tagImplicit) {
+ if (tag != tag_BitString)
+ throw new IOException("DerValue.getBitString, not a bit string "
+ + tag);
+ }
+ return buffer.getBitString();
+ }
+
+ /**
+ * Returns an ASN.1 BIT STRING value, with the tag assumed implicit
+ * based on the parameter. The bit string need not be byte-aligned.
+ *
+ * @param tagImplicit if true, the tag is assumed implicit.
+ * @return the bit string held in this value
+ */
+ public BitArray getUnalignedBitString(boolean tagImplicit)
+ throws IOException {
+ if (!tagImplicit) {
+ if (tag != tag_BitString)
+ throw new IOException("DerValue.getBitString, not a bit string "
+ + tag);
+ }
+ return buffer.getUnalignedBitString();
+ }
+
+ /**
+ * Returns an ASN.1 STRING value
+ *
+ * @return the printable string held in this value
+ */
+ public String getPrintableString()
+ throws IOException {
+ if (tag != tag_PrintableString)
+ throw new IOException(
+ "DerValue.getPrintableString, not a string " + tag);
+
+ return getASN1CharString();
+ }
+
+ /*
+ * @eturns a string if the DerValue is a ASN.1 character string type and
+ * if there is a decoder for the type. Returns null otherwise.
+ */
+ public String getASN1CharString() throws IOException {
+ try {
+ CharsetDecoder decoder = ASN1CharStrConvMap.getDefault().getDecoder(tag);
+ if (decoder == null)
+ return null;
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(length);
+
+ data.reset();
+ data.getBytes(byteBuffer.array());
+
+ CharBuffer charBuffer = decoder.decode(byteBuffer);
+ return charBuffer.toString();
+
+ } catch (CharacterCodingException e) {
+ throw new IOException("Misformed DER value", e);
+ }
+ }
+
+ /**
+ * Returns an ASN.1 T61 (Teletype) STRING value
+ *
+ * @return the teletype string held in this value
+ */
+ public String getT61String() throws IOException {
+ if (tag != tag_T61String)
+ throw new IOException(
+ "DerValue.getT61String, not T61 " + tag);
+
+ return getASN1CharString();
+ }
+
+ /**
+ * Returns an ASN.1 IA5 (ASCII) STRING value
+ *
+ * @return the ASCII string held in this value
+ */
+ public String getIA5String() throws IOException {
+ if (tag != tag_IA5String)
+ throw new IOException(
+ "DerValue.getIA5String, not IA5 " + tag);
+
+ return getASN1CharString();
+ }
+
+ public String getBMPString()
+ throws IOException {
+ if (tag != tag_BMPString)
+ throw new IOException(
+ "DerValue.getBMPString, not BMP " + tag);
+
+ return getASN1CharString();
+ }
+
+ public String getUniversalString()
+ throws IOException {
+ if (tag != tag_UniversalString)
+ throw new IOException(
+ "DerValue.getUniversalString, not UniversalString " + tag);
+
+ return getASN1CharString();
+ }
+
+ public String getUTF8String()
+ throws IOException {
+ if (tag != tag_UTF8String)
+ throw new IOException(
+ "DerValue.getUTF8String, not UTF8String " + tag);
+
+ return getASN1CharString();
+ }
+
+ /**
+ * Returns true iff the other object is a DER value which
+ * is bitwise equal to this one.
+ *
+ * @param other the object being compared with this one
+ */
+ public boolean equals(Object other) {
+ if (other instanceof DerValue)
+ return equals((DerValue) other);
+ else
+ return false;
+ }
+
+ /**
+ * Bitwise equality comparison. DER encoded values have a single
+ * encoding, so that bitwise equality of the encoded values is an
+ * efficient way to establish equivalence of the unencoded values.
+ *
+ * @param other the object being compared with this one
+ */
+ public boolean equals(DerValue other) {
+ data.reset();
+ other.data.reset();
+ if (this == other)
+ return true;
+ else if (tag != other.tag) {
+ return false;
+ } else {
+ return buffer.equals(other.buffer);
+ }
+ }
+
+ /**
+ * Returns a printable representation of the value.
+ *
+ * @return printable representation of the value
+ */
+ public String toString() {
+ try {
+ String s = getAsString();
+ if (s != null)
+ return s;
+ if (tag == tag_Null)
+ return "[DerValue, null]";
+ if (tag == tag_ObjectId)
+ return "OID." + getOID();
+
+ // integers
+ else
+ return "[DerValue, tag = " + tag
+ + ", length = " + length + "]";
+ } catch (IOException e) {
+ throw new IllegalArgumentException("misformatted DER value");
+ }
+ }
+
+ /**
+ * Returns a DER-encoded value, such that if it's passed to the
+ * DerValue constructor, a value equivalent to "this" is returned.
+ *
+ * @return DER-encoded value, including tag and length.
+ */
+ public byte[] toByteArray() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+
+ encode(out);
+ data.reset();
+ return out.toByteArray();
+ }
+
+ /**
+ * For "set" and "sequence" types, this function may be used
+ * to return a DER stream of the members of the set or sequence.
+ * This operation is not supported for primitive types such as
+ * integers or bit strings.
+ */
+ public DerInputStream toDerInputStream() throws IOException {
+ if (tag == tag_Sequence || tag == tag_Set)
+ return new DerInputStream(buffer);
+ throw new IOException("toDerInputStream rejects tag type " + tag);
+ }
+
+ /**
+ * Get the length of the encoded value.
+ */
+ public int length() {
+ return length;
+ }
+
+ /**
+ * Create the tag of the attribute.
+ *
+ * @param class the tag class type, one of UNIVERSAL, CONTEXT,
+ * APPLICATION or PRIVATE
+ * @param form if true, the value is constructed, otherwise it
+ * is primitive.
+ * @param val the tag value
+ */
+ public static byte createTag(byte tagClass, boolean form, byte val) {
+ byte tag = (byte) (tagClass | val);
+ if (form) {
+ tag |= (byte) 0x20;
+ }
+ return (tag);
+ }
+
+ /**
+ * Set the tag of the attribute. Commonly used to reset the
+ * tag value used for IMPLICIT encodings.
+ *
+ * @param tag the tag value
+ */
+ public void resetTag(byte tag) {
+ this.tag = tag;
+ }
+}
diff --git a/base/util/src/netscape/security/util/ExtPrettyPrint.java b/base/util/src/netscape/security/util/ExtPrettyPrint.java
new file mode 100644
index 000000000..90d0d094f
--- /dev/null
+++ b/base/util/src/netscape/security/util/ExtPrettyPrint.java
@@ -0,0 +1,1653 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.math.BigInteger;
+import java.text.DateFormat;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+import java.util.Vector;
+
+import netscape.security.extensions.AccessDescription;
+import netscape.security.extensions.AuthInfoAccessExtension;
+import netscape.security.extensions.CertificateScopeEntry;
+import netscape.security.extensions.CertificateScopeOfUseExtension;
+import netscape.security.extensions.ExtendedKeyUsageExtension;
+import netscape.security.extensions.InhibitAnyPolicyExtension;
+import netscape.security.extensions.NSCertTypeExtension;
+import netscape.security.extensions.OCSPNoCheckExtension;
+import netscape.security.extensions.PresenceServerExtension;
+import netscape.security.extensions.SubjectInfoAccessExtension;
+import netscape.security.x509.Attribute;
+import netscape.security.x509.AuthorityKeyIdentifierExtension;
+import netscape.security.x509.BasicConstraintsExtension;
+import netscape.security.x509.CPSuri;
+import netscape.security.x509.CRLDistributionPoint;
+import netscape.security.x509.CRLDistributionPointsExtension;
+import netscape.security.x509.CRLDistributionPointsExtension.Reason;
+import netscape.security.x509.CRLNumberExtension;
+import netscape.security.x509.CRLReasonExtension;
+import netscape.security.x509.CertificateIssuerExtension;
+import netscape.security.x509.CertificatePoliciesExtension;
+import netscape.security.x509.CertificatePolicyInfo;
+import netscape.security.x509.CertificatePolicyMap;
+import netscape.security.x509.DeltaCRLIndicatorExtension;
+import netscape.security.x509.DisplayText;
+import netscape.security.x509.Extension;
+import netscape.security.x509.FreshestCRLExtension;
+import netscape.security.x509.GeneralName;
+import netscape.security.x509.GeneralNameInterface;
+import netscape.security.x509.GeneralNames;
+import netscape.security.x509.HoldInstructionExtension;
+import netscape.security.x509.InvalidityDateExtension;
+import netscape.security.x509.IssuerAlternativeNameExtension;
+import netscape.security.x509.IssuingDistributionPoint;
+import netscape.security.x509.IssuingDistributionPointExtension;
+import netscape.security.x509.KeyIdentifier;
+import netscape.security.x509.KeyUsageExtension;
+import netscape.security.x509.NSCCommentExtension;
+import netscape.security.x509.NameConstraintsExtension;
+import netscape.security.x509.NoticeReference;
+import netscape.security.x509.OIDMap;
+import netscape.security.x509.PolicyConstraintsExtension;
+import netscape.security.x509.PolicyMappingsExtension;
+import netscape.security.x509.PolicyQualifierInfo;
+import netscape.security.x509.PolicyQualifiers;
+import netscape.security.x509.PrivateKeyUsageExtension;
+import netscape.security.x509.Qualifier;
+import netscape.security.x509.RDN;
+import netscape.security.x509.SerialNumber;
+import netscape.security.x509.SubjectAlternativeNameExtension;
+import netscape.security.x509.SubjectDirAttributesExtension;
+import netscape.security.x509.SubjectKeyIdentifierExtension;
+import netscape.security.x509.UserNotice;
+
+/**
+ * This class will display the certificate content in predefined
+ * format.
+ *
+ * @author Andrew Wnuk
+ * @version $Revision$, $Date$
+ */
+public class ExtPrettyPrint {
+
+ /*==========================================================
+ * variables
+ *==========================================================*/
+ private Extension mExt = null;
+ private ResourceBundle mResource = null;
+ private ResourceBundle resource = null;
+ private PrettyPrintFormat pp = null;
+ private int mIndentSize = 0;
+
+ DateFormat dateFormater = null;
+
+ /*==========================================================
+ * constructors
+ *==========================================================*/
+
+ public ExtPrettyPrint(Extension ext, int indentSize) {
+ mExt = ext;
+ mResource = ResourceBundle.getBundle(PrettyPrintResources.class.getName());
+ mIndentSize = indentSize;
+ pp = new PrettyPrintFormat(":");
+ }
+
+ /*==========================================================
+ * public methods
+ *==========================================================*/
+
+ /**
+ * This method return string representation of the certificate
+ * in predefined format using specified client local. I18N Support.
+ *
+ * @param clientLocale Locale to be used for localization
+ * @return string representation of the certificate
+ */
+ // public String toString(int indentSize) {
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer();
+
+ //check if the extension is known
+ if (mExt instanceof KeyUsageExtension) {
+ return getKeyUsage();
+ }
+ if (mExt instanceof NSCertTypeExtension) {
+ return getCertType();
+ }
+ if (mExt instanceof AuthorityKeyIdentifierExtension) {
+ return getAuthorityKeyIdentifier();
+ }
+ if (mExt instanceof SubjectKeyIdentifierExtension) {
+ return getSubjectKeyIdentifier();
+ }
+ if (mExt instanceof CRLReasonExtension) {
+ return getCRLReasonExtension();
+ }
+ if (mExt instanceof BasicConstraintsExtension) {
+ return getBasicConstraintsExtension();
+ }
+ if (mExt instanceof NSCCommentExtension) {
+ return getNSCCommentExtension();
+ }
+ if (mExt instanceof NameConstraintsExtension) {
+ return getNameConstraintsExtension();
+ }
+ if (mExt instanceof CRLNumberExtension) {
+ return getCRLNumberExtension();
+ }
+ if (mExt instanceof DeltaCRLIndicatorExtension) {
+ return getDeltaCRLIndicatorExtension();
+ }
+ if (mExt instanceof IssuerAlternativeNameExtension) {
+ return getIssuerAlternativeNameExtension();
+ }
+ if (mExt instanceof SubjectAlternativeNameExtension) {
+ return getSubjectAlternativeNameExtension();
+ }
+ if (mExt instanceof FreshestCRLExtension) {
+ return getFreshestCRLExtension();
+ }
+ if (mExt instanceof CRLDistributionPointsExtension) {
+ return getCRLDistributionPointsExtension();
+ }
+ if (mExt instanceof IssuingDistributionPointExtension) {
+ return getIssuingDistributionPointExtension();
+ }
+ if (mExt instanceof ExtendedKeyUsageExtension) {
+ return getExtendedKeyUsageExtension();
+ }
+ if (mExt instanceof AuthInfoAccessExtension) {
+ return getAuthInfoAccessExtension();
+ }
+ if (mExt instanceof SubjectInfoAccessExtension) {
+ return getSubjectInfoAccessExtension();
+ }
+ if (mExt instanceof OCSPNoCheckExtension) {
+ return getOCSPNoCheckExtension();
+ }
+ if (mExt instanceof PrivateKeyUsageExtension) {
+ return getPrivateKeyUsageExtension();
+ }
+ if (mExt instanceof InvalidityDateExtension) {
+ return getInvalidityDateExtension();
+ }
+ if (mExt instanceof CertificateIssuerExtension) {
+ return getCertificateIssuerExtension();
+ }
+ if (mExt instanceof HoldInstructionExtension) {
+ return getHoldInstructionExtension();
+ }
+ if (mExt instanceof PolicyConstraintsExtension) {
+ return getPolicyConstraintsExtension();
+ }
+ if (mExt instanceof PolicyMappingsExtension) {
+ return getPolicyMappingsExtension();
+ }
+ if (mExt instanceof SubjectDirAttributesExtension) {
+ return getSubjectDirAttributesExtension();
+ }
+ if (mExt instanceof CertificateScopeOfUseExtension) {
+ return getCertificateScopeOfUseExtension();
+ }
+ if (mExt instanceof PresenceServerExtension) {
+ return getPresenceServerExtension();
+ }
+
+ if (mExt instanceof InhibitAnyPolicyExtension) {
+ return getInhibitAnyPolicyExtension();
+ }
+
+ if (mExt instanceof CertificatePoliciesExtension) {
+ return getCertificatePoliciesExtension();
+ }
+
+ //unknown cert extension
+ try {
+ String extName = OIDMap.getName(mExt.getExtensionId());
+
+ if (extName == null)
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER) +
+ mExt.getExtensionId().toString() + "\n");
+ else
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER) + " " + extName + " - " +
+ mExt.getExtensionId().toString() + "\n");
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_VALUE) + "\n");
+ sb.append(pp.toHexString(mExt.getExtensionValue(), mIndentSize + 8, 16));
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+
+ }
+
+ /*==========================================================
+ * Private methods
+ *==========================================================*/
+
+ private String getNSCCommentExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NSC_COMMENT) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + ((NSCCommentExtension) mExt).toPrint(mIndentSize) + "\n");
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getNameConstraintsExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NAME_CONSTRAINTS) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ sb.append(pp.indent(mIndentSize + 4) + ((NameConstraintsExtension) mExt).toPrint(mIndentSize + 4));
+
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getOCSPNoCheckExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_OCSP_NOCHECK) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getSubjectInfoAccessExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SIA) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_ACCESS_DESC) + "\n");
+ SubjectInfoAccessExtension aia = (SubjectInfoAccessExtension) mExt;
+
+ for (int i = 0; i < aia.numberOfAccessDescription(); i++) {
+ AccessDescription ad = (AccessDescription)
+ aia.getAccessDescription(i);
+ ObjectIdentifier method = ad.getMethod();
+
+ if (method.equals(SubjectInfoAccessExtension.METHOD_OCSP)) {
+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " +
+ "ocsp" + "\n");
+ } else {
+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " +
+ method.toString() + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 8) + "Location #" + i + ": " +
+ ad.getLocation().toString() + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getAuthInfoAccessExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_AIA) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_ACCESS_DESC) + "\n");
+ AuthInfoAccessExtension aia = (AuthInfoAccessExtension) mExt;
+
+ for (int i = 0; i < aia.numberOfAccessDescription(); i++) {
+ AccessDescription ad = (AccessDescription)
+ aia.getAccessDescription(i);
+ ObjectIdentifier method = ad.getMethod();
+
+ if (method.equals(AuthInfoAccessExtension.METHOD_OCSP)) {
+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " +
+ "ocsp" + "\n");
+ } else {
+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " +
+ method.toString() + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 8) + "Location #" + i + ": " +
+ ad.getLocation().toString() + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getPresenceServerExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_PRESENCE_SERVER) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ PresenceServerExtension pse = (PresenceServerExtension) mExt;
+
+ sb.append(pp.indent(mIndentSize + 4) + "Version : " + pse.getVersion() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Street Address : " + pse.getStreetAddress() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Telephone Number : " + pse.getTelephoneNumber() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "RFC822 Name : " + pse.getRFC822() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "ID : " + pse.getID() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Host Name : " + pse.getHostName() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Port Number : " + pse.getPortNumber() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Max Users : " + pse.getMaxUsers() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + "Service Level : " + pse.getServiceLevel() + "\n");
+
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getPrivateKeyUsageExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_PRIVATE_KEY_USAGE) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ PrivateKeyUsageExtension usage = (PrivateKeyUsageExtension) mExt;
+
+ sb.append(pp.indent(mIndentSize + 4) + "Validity:\n");
+
+ if (dateFormater == null) {
+ dateFormater = DateFormat.getDateInstance(DateFormat.FULL);
+ }
+ String notBefore = dateFormater.format(usage.getNotBefore());
+ String notAfter = dateFormater.format(usage.getNotAfter());
+
+ sb.append(pp.indent(mIndentSize + 8) + "Not Before: " + notBefore + "\n");
+ sb.append(pp.indent(mIndentSize + 8) + "Not After: " + notAfter + "\n");
+
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ private String getExtendedKeyUsageExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_EXTENDED_KEY_USAGE) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_EXTENDED_KEY_USAGE) + "\n");
+ ExtendedKeyUsageExtension usage = (ExtendedKeyUsageExtension) mExt;
+ Enumeration<ObjectIdentifier> e = usage.getOIDs();
+
+ if (e != null) {
+ while (e.hasMoreElements()) {
+ ObjectIdentifier oid = (ObjectIdentifier) e.nextElement();
+
+ if (oid.equals(ExtendedKeyUsageExtension.OID_OCSP_SIGNING)) {
+ sb.append(pp.indent(mIndentSize + 8) + "OCSPSigning" + "\n");
+ } else {
+ sb.append(pp.indent(mIndentSize + 8) + oid.toString() + "\n");
+ }
+ }
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+ /**
+ * String Representation of KeyUsageExtension
+ */
+ private String getKeyUsage() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_KEY_USAGE) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_KEY_USAGE) + "\n");
+ KeyUsageExtension usage = (KeyUsageExtension) mExt;
+
+ if (((Boolean) usage.get(KeyUsageExtension.DIGITAL_SIGNATURE)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DIGITAL_SIGNATURE) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.NON_REPUDIATION)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.NON_REPUDIATION) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.KEY_ENCIPHERMENT)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_ENCIPHERMENT) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.DATA_ENCIPHERMENT)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DATA_ENCIPHERMENT) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.KEY_AGREEMENT)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_AGREEMENT) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.KEY_CERTSIGN)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_CERTSIGN) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.CRL_SIGN)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.CRL_SIGN) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.ENCIPHER_ONLY)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.ENCIPHER_ONLY) + "\n");
+ }
+ if (((Boolean) usage.get(KeyUsageExtension.DECIPHER_ONLY)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DECIPHER_ONLY) + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+
+ }
+
+ /**
+ * String Representation of NSCertTypeExtension
+ */
+ private String getCertType() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_TYPE)
+ + "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CERT_USAGE) + "\n");
+ NSCertTypeExtension type = (NSCertTypeExtension) mExt;
+
+ if (((Boolean) type.get(NSCertTypeExtension.SSL_CLIENT)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_CLIENT) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.SSL_SERVER)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_SERVER) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.EMAIL)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.EMAIL) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.OBJECT_SIGNING)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.OBJECT_SIGNING) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.SSL_CA)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_CA) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.EMAIL_CA)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.EMAIL_CA) + "\n");
+ }
+ if (((Boolean) type.get(NSCertTypeExtension.OBJECT_SIGNING_CA)).booleanValue()) {
+ sb.append(pp.indent(mIndentSize + 8)
+ + mResource.getString(NSCertTypeExtension.OBJECT_SIGNING_CA) + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+
+ }
+
+ /**
+ * String Representation of SubjectKeyIdentifierExtension
+ */
+ private String getSubjectKeyIdentifier() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SKI)
+ + "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ SubjectKeyIdentifierExtension id = (SubjectKeyIdentifierExtension) mExt;
+ KeyIdentifier keyId = (KeyIdentifier) id.get(SubjectKeyIdentifierExtension.KEY_ID);
+
+ if (keyId != null) {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_KEY_ID) + "\n");
+ sb.append(pp.toHexString(keyId.getIdentifier(), 24, 16));
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of AuthorityKeyIdentifierExtension
+ */
+ private String getAuthorityKeyIdentifier() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_AKI)
+ + "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ AuthorityKeyIdentifierExtension id = (AuthorityKeyIdentifierExtension) mExt;
+ KeyIdentifier keyId = (KeyIdentifier) id.get(AuthorityKeyIdentifierExtension.KEY_ID);
+
+ if (keyId != null) {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_KEY_ID) + "\n");
+ sb.append(pp.toHexString(keyId.getIdentifier(), mIndentSize + 8, 16));
+ // sb.append(pp.toHexString(keyId.getIdentifier(),24,16));
+ }
+ GeneralNames authNames = (GeneralNames) id.get(AuthorityKeyIdentifierExtension.AUTH_NAME);
+
+ if (authNames != null) {
+ for (int i = 0; i < authNames.size(); i++) {
+ GeneralName authName = (GeneralName) authNames.elementAt(i);
+
+ if (authName != null) {
+ sb.append(pp.indent(mIndentSize + 4)
+ + mResource.getString(PrettyPrintResources.TOKEN_AUTH_NAME) + authName.toString()
+ + "\n");
+ }
+ }
+ }
+
+ SerialNumber serial = (SerialNumber) id.get(AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
+
+ if (serial != null) {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_SERIAL) +
+ "0x" + serial.getNumber().toBigInteger().toString(16).toUpperCase() + "\n");
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of CRLReasonExtension
+ */
+ private String getCRLReasonExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_REVOCATION_REASON) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ CRLReasonExtension ext = (CRLReasonExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_REASON) +
+ ext.getReason().toString() + "\n");
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of InhibitAnyPolicyExtension
+ */
+ private String getInhibitAnyPolicyExtension() {
+ StringBuffer sb = new StringBuffer();
+ try {
+ sb.append(pp.indent(mIndentSize) +
+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_INHIBIT_ANY_POLICY_EXT) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ InhibitAnyPolicyExtension ext = (InhibitAnyPolicyExtension) mExt;
+ if (((Extension) mExt).isCritical())
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ else
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_SKIP_CERTS));
+ BigInt num = ext.getSkipCerts();
+ sb.append("" + num.toInt() + "\n");
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of BasicConstraintsExtension
+ */
+ private String getBasicConstraintsExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_BASIC_CONSTRAINTS) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ BasicConstraintsExtension ext = (BasicConstraintsExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_IS_CA));
+ boolean isCA = ((Boolean) ext.get(BasicConstraintsExtension.IS_CA)).booleanValue();
+
+ if (isCA) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ Integer pathLength = (Integer) ext.get(BasicConstraintsExtension.PATH_LEN);
+
+ if (pathLength != null) {
+ if (pathLength.longValue() >= 0) {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) +
+ pathLength.toString() + "\n");
+ } else if (pathLength.longValue() == -1 || pathLength.longValue() == -2) {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) +
+ mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN_UNLIMITED) + "\n");
+ } else {
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) +
+ mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN_INVALID) +
+ " (" + pathLength.toString() + ")\n");
+ }
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of CRLNumberExtension
+ */
+ private String getCRLNumberExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CRL_NUMBER) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ CRLNumberExtension ext = (CRLNumberExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ BigInteger crlNumber = (BigInteger) ext.get(CRLNumberExtension.NUMBER);
+
+ if (crlNumber != null) {
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_NUMBER) +
+ crlNumber.toString() + "\n");
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of DeltaCRLIndicatorExtension
+ */
+ private String getDeltaCRLIndicatorExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_DELTA_CRL_INDICATOR) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ DeltaCRLIndicatorExtension ext = (DeltaCRLIndicatorExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ BigInteger crlNumber = (BigInteger) ext.get(DeltaCRLIndicatorExtension.NUMBER);
+
+ if (crlNumber != null) {
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_BASE_CRL_NUMBER) +
+ crlNumber.toString() + "\n");
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of IssuerAlternativeName Extension
+ */
+ private String getIssuerAlternativeNameExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_ISSUER_ALT_NAME) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ IssuerAlternativeNameExtension ext = (IssuerAlternativeNameExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ GeneralNames issuerNames = (GeneralNames) ext.get(IssuerAlternativeNameExtension.ISSUER_NAME);
+
+ if (issuerNames != null) {
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_ISSUER_NAMES) + "\n");
+ for (int i = 0; i < issuerNames.size(); i++) {
+ GeneralName issuerName = (GeneralName) issuerNames.elementAt(i);
+
+ if (issuerName != null) {
+ String nameType = "";
+
+ if (issuerName.getType() == GeneralNameInterface.NAME_DIRECTORY)
+ nameType = "DirectoryName: ";
+ sb.append(pp.indent(mIndentSize + 8) + nameType + issuerName.toString() + "\n");
+ }
+ }
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of SubjectAlternativeName Extension
+ */
+ private String getSubjectAlternativeNameExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SUBJECT_ALT_NAME) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ SubjectAlternativeNameExtension ext = (SubjectAlternativeNameExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ GeneralNames subjectNames = (GeneralNames) ext.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_VALUE) + "\n");
+ for (int i = 0; i < subjectNames.size(); i++) {
+ GeneralName subjectName = (GeneralName) subjectNames.elementAt(i);
+
+ if (subjectName != null) {
+ String nameType = "";
+
+ if (subjectName.getType() == GeneralNameInterface.NAME_DIRECTORY)
+ nameType = "DirectoryName: ";
+ sb.append(pp.indent(mIndentSize + 8) + nameType + subjectName.toString() + "\n");
+ }
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of CertificateScopeOfUse Extension
+ */
+ private String getCertificateScopeOfUseExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_SCOPE_OF_USE) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ CertificateScopeOfUseExtension ext = (CertificateScopeOfUseExtension) mExt;
+
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ Vector<CertificateScopeEntry> entries = ext.getCertificateScopeEntries();
+
+ if (entries != null) {
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_SCOPE_OF_USE) + "\n");
+ for (int i = 0; i < entries.size(); i++) {
+ CertificateScopeEntry se = (CertificateScopeEntry) entries.elementAt(i);
+ GeneralName gn = se.getGeneralName();
+
+ if (gn != null) {
+ String nameType = "";
+
+ if (gn.getType() == GeneralNameInterface.NAME_DIRECTORY)
+ nameType = "DirectoryName: ";
+ sb.append(pp.indent(mIndentSize + 8) + nameType + gn.toString() + "\n");
+ }
+ BigInt port = se.getPort();
+
+ if (port != null) {
+ sb.append(pp.indent(mIndentSize + 8) + PrettyPrintResources.TOKEN_PORT +
+ port.toBigInteger().toString() + "\n");
+ }
+ }
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of FreshestCRLExtension
+ */
+ private String getFreshestCRLExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+
+ //
+ // Generic stuff: name, OID, criticality
+ //
+ sb.append(pp.indent(mIndentSize) +
+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_FRESHEST_CRL_EXT) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ //
+ // Now the CRLDP-specific stuff
+ //
+ FreshestCRLExtension ext = (FreshestCRLExtension) mExt;
+
+ int numPoints = ext.getNumPoints();
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRLDP_NUMPOINTS)
+ + numPoints + "\n");
+
+ for (int i = 0; i < numPoints; i++) {
+
+ //
+ // print one individual CRL distribution point
+ //
+
+ int idt;
+
+ idt = mIndentSize + 4; // reset each time through loop
+ boolean isEmpty = true;
+
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_POINTN) +
+ i + "\n");
+
+ CRLDistributionPoint pt = ext.getPointAt(i);
+
+ idt += 4; // further indent rest of information
+
+ if (pt.getFullName() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT)
+ + pt.getFullName() + "\n");
+ }
+
+ if (pt.getRelativeName() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT)
+ + pt.getRelativeName() + "\n");
+ }
+
+ if (pt.getReasons() != null) {
+ isEmpty = false;
+ byte[] reasonBits = pt.getReasons().toByteArray();
+ String reasonList = reasonBitsToReasonList(reasonBits);
+
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_REASONS)
+ + reasonList + "\n");
+ }
+
+ if (pt.getCRLIssuer() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_CRLISSUER)
+ + pt.getCRLIssuer() + "\n");
+ }
+
+ if (isEmpty) {
+ sb.append(pp.indent(idt) + "<i>empty</i>\n");
+ }
+
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of CRLDistributionPointsExtension
+ */
+ private String getCRLDistributionPointsExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+
+ //
+ // Generic stuff: name, OID, criticality
+ //
+ sb.append(pp.indent(mIndentSize) +
+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_CRL_DP_EXT) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ //
+ // Now the CRLDP-specific stuff
+ //
+ CRLDistributionPointsExtension ext =
+ (CRLDistributionPointsExtension) mExt;
+
+ int numPoints = ext.getNumPoints();
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRLDP_NUMPOINTS)
+ + numPoints + "\n");
+
+ for (int i = 0; i < numPoints; i++) {
+
+ //
+ // print one individual CRL distribution point
+ //
+
+ int idt;
+
+ idt = mIndentSize + 4; // reset each time through loop
+ boolean isEmpty = true;
+
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_POINTN) +
+ i + "\n");
+
+ CRLDistributionPoint pt = ext.getPointAt(i);
+
+ idt += 4; // further indent rest of information
+
+ if (pt.getFullName() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT)
+ + pt.getFullName() + "\n");
+ }
+
+ if (pt.getRelativeName() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT)
+ + pt.getRelativeName() + "\n");
+ }
+
+ if (pt.getReasons() != null) {
+ isEmpty = false;
+ byte[] reasonBits = pt.getReasons().toByteArray();
+ String reasonList = reasonBitsToReasonList(reasonBits);
+
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_REASONS)
+ + reasonList + "\n");
+ }
+
+ if (pt.getCRLIssuer() != null) {
+ isEmpty = false;
+ sb.append(pp.indent(idt) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_CRLISSUER)
+ + pt.getCRLIssuer() + "\n");
+ }
+
+ if (isEmpty) {
+ sb.append(pp.indent(idt) + "<i>empty</i>\n");
+ }
+
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ private static String reasonBitsToReasonList(byte[] reasonBits) {
+
+ Reason[] reasons = Reason.bitArrayToReasonArray(reasonBits);
+
+ if (reasons.length == 0) {
+ return "";
+ } else {
+ StringBuffer buf = new StringBuffer();
+
+ buf.append(reasons[0].getName());
+ for (int i = 1; i < reasons.length; i++) {
+ buf.append(", ");
+ buf.append(reasons[i].getName());
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
+ * String Representation of IssuerAlternativeName Extension
+ */
+ private String getIssuingDistributionPointExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_ISSUING_DIST_POINT) + "- " +
+ mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ IssuingDistributionPointExtension ext = (IssuingDistributionPointExtension) mExt;
+ IssuingDistributionPoint issuingDistributionPoint = ext.getIssuingDistributionPoint();
+
+ if (issuingDistributionPoint != null) {
+ GeneralNames fullNames = issuingDistributionPoint.getFullName();
+ RDN relativeName = issuingDistributionPoint.getRelativeName();
+
+ if (fullNames != null || relativeName != null) {
+ sb.append(pp.indent(mIndentSize + 4)
+ + mResource.getString(PrettyPrintResources.TOKEN_DIST_POINT_NAME) + "\n");
+ if (fullNames != null) {
+ sb.append(pp.indent(mIndentSize + 8)
+ + mResource.getString(PrettyPrintResources.TOKEN_FULL_NAME) + "\n");
+ for (int i = 0; i < fullNames.size(); i++) {
+ GeneralName fullName = (GeneralName) fullNames.elementAt(i);
+
+ if (fullName != null) {
+ sb.append(pp.indent(mIndentSize + 12) + fullName.toString() + "\n");
+ }
+ }
+ }
+ if (relativeName != null) {
+ sb.append(pp.indent(mIndentSize + 8)
+ + mResource.getString(PrettyPrintResources.TOKEN_RELATIVE_NAME) +
+ relativeName.toString() + "\n");
+ }
+ }
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_ONLY_USER_CERTS));
+ if (issuingDistributionPoint.getOnlyContainsUserCerts()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_ONLY_CA_CERTS));
+ if (issuingDistributionPoint.getOnlyContainsCACerts()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ BitArray onlySomeReasons = issuingDistributionPoint.getOnlySomeReasons();
+
+ if (onlySomeReasons != null) {
+ sb.append(pp.indent(mIndentSize + 4)
+ + mResource.getString(PrettyPrintResources.TOKEN_ONLY_SOME_REASONS));
+ sb.append("0x" + pp.toHexString(onlySomeReasons.toByteArray()));
+ }
+
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_INDIRECT_CRL));
+ if (issuingDistributionPoint.getIndirectCRL()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of InvalidityDateExtension
+ */
+ private String getInvalidityDateExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_INVALIDITY_DATE) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ InvalidityDateExtension ext = (InvalidityDateExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_DATE_OF_INVALIDITY) +
+ ext.getInvalidityDate().toString() + "\n");
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of CertificateIssuerExtension
+ */
+ private String getCertificateIssuerExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERTIFICATE_ISSUER) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ CertificateIssuerExtension ext = (CertificateIssuerExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ GeneralNames issuerNames = (GeneralNames) ext.get(
+ CertificateIssuerExtension.CERTIFICATE_ISSUER);
+
+ if (issuerNames != null) {
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_ISSUER_NAMES) + "\n");
+ for (int i = 0; i < issuerNames.size(); i++) {
+ GeneralName issuerName = (GeneralName) issuerNames.elementAt(i);
+
+ if (issuerName != null) {
+ String nameType = "";
+
+ if (issuerName.getType() == GeneralNameInterface.NAME_DIRECTORY)
+ nameType = "DirectoryName: ";
+ sb.append(pp.indent(mIndentSize + 8) + nameType + issuerName.toString() + "\n");
+ }
+ }
+ }
+
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of HoldInstructionExtension
+ */
+ private String getHoldInstructionExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_HOLD_INSTRUCTION) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ HoldInstructionExtension ext = (HoldInstructionExtension) mExt;
+
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_HOLD_INSTRUCTION_CODE) +
+ ext.getHoldInstructionCodeDescription() + "\n");
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of PolicyConstraintsExtension
+ */
+ private String getPolicyConstraintsExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(
+ mResource.getString(
+ PrettyPrintResources.TOKEN_POLICY_CONSTRAINTS) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ PolicyConstraintsExtension ext = (PolicyConstraintsExtension) mExt;
+ int require = ext.getRequireExplicitMapping();
+ int inhibit = ext.getInhibitPolicyMapping();
+
+ sb.append(
+ pp.indent(mIndentSize + 4) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_REQUIRE_EXPLICIT_POLICY) +
+ ((require == -1) ?
+ mResource.getString(PrettyPrintResources.TOKEN_NOT_SET) :
+ String.valueOf(require)) + "\n");
+ sb.append(
+ pp.indent(mIndentSize + 4) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_INHIBIT_POLICY_MAPPING) +
+ ((inhibit == -1) ?
+ mResource.getString(PrettyPrintResources.TOKEN_NOT_SET) :
+ String.valueOf(inhibit)) + "\n");
+ return sb.toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of PolicyMappingsExtension
+ */
+ private String getPolicyMappingsExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_POLICY_MAPPINGS) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ PolicyMappingsExtension ext = (PolicyMappingsExtension) mExt;
+ Enumeration<CertificatePolicyMap> maps = ext.getMappings();
+
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_MAPPINGS));
+ if (maps == null || !maps.hasMoreElements()) {
+ sb.append(
+ mResource.getString(PrettyPrintResources.TOKEN_NONE) + "\n");
+ } else {
+ sb.append("\n");
+ for (int i = 0; maps.hasMoreElements(); i++) {
+ sb.append(pp.indent(mIndentSize + 8) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_MAP) + i + ":" + "\n");
+ CertificatePolicyMap m =
+ (CertificatePolicyMap) maps.nextElement();
+
+ sb.append(pp.indent(mIndentSize + 12) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_ISSUER_DOMAIN_POLICY) +
+ m.getIssuerIdentifier().getIdentifier().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 12) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_SUBJECT_DOMAIN_POLICY) +
+ m.getSubjectIdentifier().getIdentifier().toString() + "\n");
+ }
+ }
+ return sb.toString();
+ } catch (Throwable e) {
+ return "";
+ }
+ }
+
+ /**
+ * String Representation of SubjectDirAttributesExtension
+ */
+ private String getSubjectDirAttributesExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SUBJECT_DIR_ATTR) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL));
+ if (((Extension) mExt).isCritical()) {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+
+ SubjectDirAttributesExtension ext =
+ (SubjectDirAttributesExtension) mExt;
+
+ sb.append(pp.indent(mIndentSize + 4) +
+ mResource.getString(PrettyPrintResources.TOKEN_ATTRIBUTES));
+ Enumeration<Attribute> attrs = ext.getAttributesList();
+
+ if (attrs == null || !attrs.hasMoreElements()) {
+ sb.append(
+ mResource.getString(PrettyPrintResources.TOKEN_NONE) + "\n");
+ } else {
+ sb.append("\n");
+ for (int j = 0; attrs.hasMoreElements(); j++) {
+ Attribute attr = (Attribute) attrs.nextElement();
+
+ sb.append(pp.indent(mIndentSize + 8) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_ATTRIBUTE) + j + ":" + "\n");
+ sb.append(pp.indent(mIndentSize + 12) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER) +
+ attr.getOid().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 12) +
+ mResource.getString(
+ PrettyPrintResources.TOKEN_VALUES));
+ Enumeration<String> values = attr.getValues();
+
+ if (values == null || !values.hasMoreElements()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NONE) + "\n");
+ } else {
+ for (int k = 0; values.hasMoreElements(); k++) {
+ String v = (String) values.nextElement();
+
+ if (k != 0)
+ sb.append(",");
+ sb.append(v);
+ }
+ }
+ sb.append("\n");
+ }
+ }
+ return sb.toString();
+ } catch (Throwable e) {
+ return "";
+ }
+ }
+
+ private String getCertificatePoliciesExtension() {
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ sb.append(pp.indent(mIndentSize) + mResource.getString(
+ PrettyPrintResources.TOKEN_IDENTIFIER));
+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_POLICIES) +
+ "- " + mExt.getExtensionId().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CRITICAL));
+ if (mExt.isCritical()) {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_YES) + "\n");
+ } else {
+ sb.append(mResource.getString(
+ PrettyPrintResources.TOKEN_NO) + "\n");
+ }
+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(
+ PrettyPrintResources.TOKEN_CERT_POLICIES) + "\n");
+ CertificatePoliciesExtension cp = (CertificatePoliciesExtension) mExt;
+ @SuppressWarnings("unchecked")
+ Vector<CertificatePolicyInfo> cpv = (Vector<CertificatePolicyInfo>) cp.get("infos");
+ Enumeration<CertificatePolicyInfo> e = cpv.elements();
+
+ if (e != null) {
+ while (e.hasMoreElements()) {
+ CertificatePolicyInfo cpi = e.nextElement();
+
+ sb.append(pp.indent(mIndentSize + 8)
+ + "Policy Identifier: " + cpi.getPolicyIdentifier().getIdentifier().toString() + "\n");
+ PolicyQualifiers cpq = cpi.getPolicyQualifiers();
+ if (cpq != null) {
+ for (int i = 0; i < cpq.size(); i++) {
+ PolicyQualifierInfo pq = cpq.getInfoAt(i);
+ Qualifier q = pq.getQualifier();
+ if (q instanceof CPSuri) {
+ sb.append(pp.indent(mIndentSize + 12)
+ + "Policy Qualifier Identifier: CPS Pointer Qualifier - "
+ + pq.getId() + "\n");
+ sb.append(pp.indent(mIndentSize + 12)
+ + "Policy Qualifier Data: " + ((CPSuri) q).getURI() + "\n");
+ } else if (q instanceof UserNotice) {
+ sb.append(pp.indent(mIndentSize + 12)
+ + "Policy Qualifier Identifier: CPS User Notice Qualifier - "
+ + pq.getId() + "\n");
+ NoticeReference nref = ((UserNotice) q).getNoticeReference();
+ DisplayText dt = ((UserNotice) q).getDisplayText();
+ sb.append(pp.indent(mIndentSize + 12) + "Policy Qualifier Data: \n");
+ if (nref != null) {
+ sb.append(pp.indent(mIndentSize + 16)
+ + "Organization: " + nref.getOrganization().toString() + "\n");
+ sb.append(pp.indent(mIndentSize + 16) + "Notice Numbers: ");
+ int[] nums = nref.getNumbers();
+ for (int k = 0; k < nums.length; k++) {
+ if (k != 0) {
+ sb.append(",");
+ sb.append(nums[k]);
+ } else {
+ sb.append(nums[k]);
+ }
+ }
+ sb.append("\n");
+ }
+ if (dt != null) {
+ sb.append(pp.indent(mIndentSize + 16) + "Explicit Text: " + dt.toString() + "\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return sb.toString();
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/util/IA5Charset.java b/base/util/src/netscape/security/util/IA5Charset.java
new file mode 100644
index 000000000..db6da2331
--- /dev/null
+++ b/base/util/src/netscape/security/util/IA5Charset.java
@@ -0,0 +1,24 @@
+package netscape.security.util;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+public class IA5Charset extends Charset {
+
+ public IA5Charset() {
+ super("ASN.1-IA5", null);
+ }
+
+ public boolean contains(Charset cs) {
+ return false;
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new IA5CharsetDecoder(this);
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new IA5CharsetEncoder(this);
+ }
+}
diff --git a/base/util/src/netscape/security/util/IA5CharsetDecoder.java b/base/util/src/netscape/security/util/IA5CharsetDecoder.java
new file mode 100644
index 000000000..620d65aca
--- /dev/null
+++ b/base/util/src/netscape/security/util/IA5CharsetDecoder.java
@@ -0,0 +1,62 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Converts bytes in ASN.1 IA5String character set to IA5String characters.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class IA5CharsetDecoder extends CharsetDecoder {
+
+ public IA5CharsetDecoder(Charset cs) {
+ super(cs, 1, 1);
+ }
+
+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+
+ while (true) {
+
+ if (in.remaining() < 1)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ byte b = in.get();
+
+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && (b & 0x80) != 0) {
+ return CoderResult.unmappableForLength(1);
+ }
+
+ if (out.remaining() < 1) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put((char) (b & 0x7f));
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/util/IA5CharsetEncoder.java b/base/util/src/netscape/security/util/IA5CharsetEncoder.java
new file mode 100644
index 000000000..dad0c9a2d
--- /dev/null
+++ b/base/util/src/netscape/security/util/IA5CharsetEncoder.java
@@ -0,0 +1,69 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Converts characters in ASN.1 IA5String character set to IA5String bytes.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class IA5CharsetEncoder extends CharsetEncoder {
+
+ public IA5CharsetEncoder(Charset cs) {
+ super(cs, 1, 1);
+ }
+
+ /*
+ * Converts an array of Unicode characters into an array of IA5String
+ * bytes and returns the conversion result.
+ * @param in input character buffer to convert.
+ * @param out byte buffer to store output.
+ * @return encoding result.
+ */
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+
+ while (true) {
+
+ if (in.remaining() < 1)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ char c = in.get();
+
+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && (c & 0xFF80) != 0) {
+ return CoderResult.unmappableForLength(1);
+ }
+
+ if (out.remaining() < 1) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put((byte) (c & 0x7f));
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/util/ObjectIdentifier.java b/base/util/src/netscape/security/util/ObjectIdentifier.java
new file mode 100644
index 000000000..6ff02d1b0
--- /dev/null
+++ b/base/util/src/netscape/security/util/ObjectIdentifier.java
@@ -0,0 +1,426 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+/**
+ * Represent an ISO Object Identifier.
+ *
+ * <P>
+ * Object Identifiers are arbitrary length hierarchical identifiers. The individual components are numbers, and they
+ * define paths from the root of an ISO-managed identifier space. You will sometimes see a string name used instead of
+ * (or in addition to) the numerical id. These are synonyms for the numerical IDs, but are not widely used since most
+ * sites do not know all the requisite strings, while all sites can parse the numeric forms.
+ *
+ * <P>
+ * So for example, JavaSoft has the sole authority to assign the meaning to identifiers below the 1.3.6.1.4.42.2.17 node
+ * in the hierarchy, and other organizations can easily acquire the ability to assign such unique identifiers.
+ *
+ * @version 1.23
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+final public class ObjectIdentifier implements Serializable {
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = 8697030238860181294L;
+
+ /**
+ * Constructs an object identifier from a string. This string
+ * should be of the form 1.23.34.45.56 etc.
+ */
+ public ObjectIdentifier(String oid) {
+ if (oid == null)
+ return;
+
+ int ch = '.';
+ int start = 0;
+ int end = 0;
+
+ // Calculate length of oid
+ componentLen = 0;
+ while ((end = oid.indexOf(ch, start)) != -1) {
+ start = end + 1;
+ componentLen += 1;
+ }
+ componentLen += 1;
+ components = new int[componentLen];
+
+ start = 0;
+ int i = 0;
+ String comp = null;
+ while ((end = oid.indexOf(ch, start)) != -1) {
+ comp = oid.substring(start, end);
+ components[i++] = Integer.valueOf(comp).intValue();
+ start = end + 1;
+ }
+ comp = oid.substring(start);
+ components[i] = Integer.valueOf(comp).intValue();
+ }
+
+ /**
+ * Constructs an object ID from an array of integers. This
+ * is used to construct constant object IDs.
+ */
+ public ObjectIdentifier(int values[]) {
+ try {
+ components = (int[]) values.clone();
+ componentLen = values.length;
+ } catch (Throwable t) {
+ System.out.println("X509.ObjectIdentifier(), no cloning!");
+ }
+ }
+
+ /**
+ * Constructs an object ID from an ASN.1 encoded input stream.
+ * The encoding of the ID in the stream uses "DER", a BER/1 subset.
+ * In this case, that means a triple { typeId, length, data }.
+ *
+ * <P>
+ * <STRONG>NOTE:</STRONG> When an exception is thrown, the input stream has not been returned to its "initial"
+ * state.
+ *
+ * @param in DER-encoded data holding an object ID
+ * @exception IOException indicates a decoding error
+ */
+ public ObjectIdentifier(DerInputStream in)
+ throws IOException {
+ byte type_id;
+ int bufferEnd;
+
+ /*
+ * Object IDs are a "universal" type, and their tag needs only
+ * one byte of encoding. Verify that the tag of this datum
+ * is that of an object ID.
+ *
+ * Then get and check the length of the ID's encoding. We set
+ * up so that we can use in.available() to check for the end of
+ * this value in the data stream.
+ */
+ type_id = (byte) in.getByte();
+ if (type_id != DerValue.tag_ObjectId)
+ throw new IOException(
+ "X509.ObjectIdentifier() -- data isn't an object ID"
+ + " (tag = " + type_id + ")");
+
+ bufferEnd = in.available() - in.getLength() - 1;
+ if (bufferEnd < 0)
+ throw new IOException(
+ "X509.ObjectIdentifier() -- not enough data");
+
+ initFromEncoding(in, bufferEnd);
+ }
+
+ /*
+ * Build the OID from the rest of a DER input buffer; the tag
+ * and length have been removed/verified
+ */
+ ObjectIdentifier(DerInputBuffer buf) throws IOException {
+ initFromEncoding(new DerInputStream(buf), 0);
+ }
+
+ /*
+ * Helper function -- get the OID from a stream, after tag and
+ * length are verified.
+ */
+ private void initFromEncoding(DerInputStream in, int bufferEnd)
+ throws IOException {
+
+ /*
+ * Now get the components ("sub IDs") one at a time. We fill a
+ * temporary buffer, resizing it as needed.
+ */
+ int component;
+ boolean first_subid = true;
+
+ for (components = new int[allocationQuantum], componentLen = 0; in.available() > bufferEnd;) {
+ component = getComponent(in);
+
+ if (first_subid) {
+ int X, Y;
+
+ /*
+ * The ISO root has three children (0, 1, 2) and those nodes
+ * aren't allowed to assign IDs larger than 39. These rules
+ * are memorialized by some special casing in the BER encoding
+ * of object IDs ... or maybe it's vice versa.
+ *
+ * NOTE: the allocation quantum is large enough that we know
+ * we don't have to reallocate here!
+ */
+ if (component < 40)
+ X = 0;
+ else if (component < 80)
+ X = 1;
+ else
+ X = 2;
+ Y = component - (X * 40);
+
+ components[0] = X;
+ components[1] = Y;
+ componentLen = 2;
+
+ first_subid = false;
+
+ } else {
+
+ /*
+ * Other components are encoded less exotically. The only
+ * potential trouble is the need to grow the array.
+ */
+ if (componentLen >= components.length) {
+ int tmp_components[];
+
+ tmp_components = new int[components.length
+ + allocationQuantum];
+ System.arraycopy(components, 0, tmp_components, 0,
+ components.length);
+ components = tmp_components;
+ }
+ components[componentLen++] = component;
+ }
+ }
+
+ /*
+ * Final sanity check -- if we didn't use exactly the number of bytes
+ * specified, something's quite wrong.
+ */
+ if (in.available() != bufferEnd) {
+ throw new IOException(
+ "X509.ObjectIdentifier() -- malformed input data");
+ }
+ }
+
+ /*
+ * n.b. the only public interface is DerOutputStream.putOID()
+ */
+ void encode(DerOutputStream out) throws IOException {
+ DerOutputStream bytes = new DerOutputStream();
+ int i;
+
+ bytes.write((components[0] * 40) + components[1]);
+ for (i = 2; i < componentLen; i++)
+ putComponent(bytes, components[i]);
+
+ /*
+ * Now that we've constructed the component, encode
+ * it in the stream we were given.
+ */
+ out.write(DerValue.tag_ObjectId, bytes);
+ }
+
+ /*
+ * Tricky OID component parsing technique ... note that one bit
+ * per octet is lost, this returns at most 28 bits of component.
+ * Also, notice this parses in big-endian format.
+ */
+ private static int getComponent(DerInputStream in)
+ throws IOException {
+ int retval, i, tmp;
+
+ for (i = 0, retval = 0; i < 4; i++) {
+ retval <<= 7;
+ tmp = in.getByte();
+ retval |= (tmp & 0x07f);
+ if ((tmp & 0x080) == 0)
+ return retval;
+ }
+
+ throw new IOException("X509.OID, component value too big");
+ }
+
+ /*
+ * Reverse of the above routine. Notice it needs to emit in
+ * big-endian form, so it buffers the output until it's ready.
+ * (Minimum length encoding is a DER requirement.)
+ */
+ private static void putComponent(DerOutputStream out, int val)
+ throws IOException {
+ int i;
+ byte buf[] = new byte[4];
+
+ for (i = 0; i < 4; i++) {
+ buf[i] = (byte) (val & 0x07f);
+ val >>>= 7;
+ if (val == 0)
+ break;
+ }
+ for (; i > 0; --i)
+ out.write(buf[i] | 0x080);
+ out.write(buf[0]);
+ }
+
+ // XXX this API should probably facilitate the JDK sort utility
+
+ /**
+ * Compares this identifier with another, for sorting purposes.
+ * An identifier does not precede itself.
+ *
+ * @param other identifer that may precede this one.
+ * @return true iff <em>other</em> precedes this one
+ * in a particular sorting order.
+ */
+ public boolean precedes(ObjectIdentifier other) {
+ int i;
+
+ // shorter IDs go first
+ if (other == this || componentLen < other.componentLen)
+ return false;
+ if (other.componentLen < componentLen)
+ return true;
+
+ // for each component, the lesser component goes first
+ for (i = 0; i < componentLen; i++) {
+ if (other.components[i] < components[i])
+ return true;
+ }
+
+ // identical IDs don't precede each other
+ return false;
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof ObjectIdentifier)
+ return equals((ObjectIdentifier) other);
+ else
+ return false;
+ }
+
+ /**
+ * Compares this identifier with another, for equality.
+ *
+ * @return true iff the names are identical.
+ */
+ public boolean equals(ObjectIdentifier other) {
+ int i;
+
+ if (other == this)
+ return true;
+ if (componentLen != other.componentLen)
+ return false;
+ for (i = 0; i < componentLen; i++) {
+ if (components[i] != other.components[i])
+ return false;
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int h = 0;
+ int oflow = 0;
+
+ for (int i = 0; i < componentLen; i++) {
+ oflow = (h & 0xff800000) >> 23;
+ h <<= 9;
+ h += components[i];
+ h ^= oflow;
+ }
+ return h;
+ }
+
+ /**
+ * Returns a string form of the object ID. The format is the
+ * conventional "dot" notation for such IDs, without any
+ * user-friendly descriptive strings, since those strings
+ * will not be understood everywhere.
+ */
+ public String toString() {
+ String retval;
+ int i;
+
+ for (i = 0, retval = ""; i < componentLen; i++) {
+ if (i != 0)
+ retval += ".";
+ retval += components[i];
+ }
+ return retval;
+ }
+
+ /*
+ * To simplify, we assume no individual component of an object ID is
+ * larger than 32 bits. Then we represent the path from the root as
+ * an array that's (usually) only filled at the beginning.
+ */
+ private int components[]; // path from root
+ private int componentLen; // how much is used.
+
+ private static final int allocationQuantum = 5; // >= 2
+
+ /**
+ * Netscape Enhancement:
+ * This function implements a object identifier factory. It
+ * should help reduces in-memory Object Identifier object.
+ * This function also provide additional checking on the OID.
+ * A valid OID should start with 0, 1, or 2.
+ *
+ * Notes:
+ * This function never returns null. IOException is raised
+ * in error conditions.
+ */
+ public static Hashtable<String, ObjectIdentifier> mOIDs = new Hashtable<String, ObjectIdentifier>();
+
+ public static ObjectIdentifier getObjectIdentifier(String oid)
+ throws IOException {
+ int value;
+
+ if (oid == null)
+ throw new IOException("empty object identifier");
+
+ oid = oid.trim();
+
+ ObjectIdentifier thisOID = mOIDs.get(oid);
+ if (thisOID != null)
+ return thisOID;
+
+ StringTokenizer token = new StringTokenizer(oid, ".");
+ value = new Integer(token.nextToken()).intValue();
+ /* First token should be 0, 1, 2 */
+ if (value >= 0 && value <= 2) {
+ value = new Integer(token.nextToken()).intValue();
+ /* Second token should be 0 <= && >= 39 */
+ if (value >= 0 && value <= 39) {
+ thisOID = new ObjectIdentifier(oid);
+ if (thisOID.toString().equals(oid)) {
+ mOIDs.put(oid, thisOID);
+ return thisOID;
+ }
+ throw new IOException("invalid oid " + oid);
+ } else
+ throw new IOException("invalid oid " + oid);
+ } else
+ throw new IOException("invalid oid " + oid);
+ }
+
+ public static ObjectIdentifier getObjectIdentifier(int values[])
+ throws IOException {
+ String retval;
+ int i;
+
+ for (i = 0, retval = ""; i < values.length; i++) {
+ if (i != 0)
+ retval += ".";
+ retval += values[i];
+ }
+ return getObjectIdentifier(retval);
+ }
+}
diff --git a/base/util/src/netscape/security/util/PrettyPrintFormat.java b/base/util/src/netscape/security/util/PrettyPrintFormat.java
new file mode 100644
index 000000000..25bc23d26
--- /dev/null
+++ b/base/util/src/netscape/security/util/PrettyPrintFormat.java
@@ -0,0 +1,160 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+/**
+ * This class will display the certificate content in predefined
+ * format.
+ *
+ * @author Andrew Wnuk
+ * @version $Revision$, $Date$
+ */
+public class PrettyPrintFormat {
+
+ /*==========================================================
+ * variables
+ *==========================================================*/
+ private String mSeparator = "";
+ private int mIndentSize = 0;
+ private int mLineLen = 0;
+
+ /*==========================================================
+ * constants
+ *
+ *==========================================================*/
+ private final static String spaces =
+ " " +
+ " " +
+ " " +
+ " " +
+ " ";
+
+ /*==========================================================
+ * constructors
+ *==========================================================*/
+
+ public PrettyPrintFormat(String separator) {
+ mSeparator = separator;
+ }
+
+ public PrettyPrintFormat(String separator, int lineLen) {
+ mSeparator = separator;
+ mLineLen = lineLen;
+ }
+
+ public PrettyPrintFormat(String separator, int lineLen, int indentSize) {
+ mSeparator = separator;
+ mLineLen = lineLen;
+ mIndentSize = indentSize;
+ }
+
+ /*==========================================================
+ * Private methods
+ *==========================================================*/
+
+ /*==========================================================
+ * public methods
+ *==========================================================*/
+
+ /**
+ * Provide white space indention
+ * stevep - speed improvements. Factor of 10 improvement
+ *
+ * @param numSpace number of white space to be returned
+ * @return white spaces
+ */
+ public String indent(int size) {
+ return spaces.substring(0, size);
+ }
+
+ private static final char[] hexdigits = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ /**
+ * Convert Byte Array to Hex String Format
+ * stevep - speedup by factor of 8
+ *
+ * @param byte array of data to hexify
+ * @param indentSize number of spaces to prepend before each line
+ * @param lineLen number of bytes to output on each line (0
+ * means: put everything on one line
+ * @param separator the first character of this string will be used as
+ * the separator between bytes.
+ * @return string representation
+ */
+
+ public String toHexString(byte[] in, int indentSize,
+ int lineLen, String separator) {
+ StringBuffer sb = new StringBuffer();
+ int hexCount = 0;
+ char c[];
+ int j = 0;
+
+ if (lineLen == 0) {
+ c = new char[in.length * 3 + 1];
+ } else {
+ c = new char[lineLen * 3 + 1];
+ }
+
+ char sep = separator.charAt(0);
+
+ sb.append(indent(indentSize));
+ for (int i = 0; i < in.length; i++) {
+ if (lineLen > 0 && hexCount == lineLen) {
+ c[j++] = '\n';
+ sb.append(c, 0, j);
+ sb.append(indent(indentSize));
+ hexCount = 0;
+ j = 0;
+ }
+ byte x = in[i];
+
+ // output hex digits to buffer
+ c[j++] = hexdigits[(char) ((x >> 4) & 0xf)];
+ c[j++] = hexdigits[(char) (x & 0xf)];
+
+ // if not last char, output separator
+ if (i != in.length - 1) {
+ c[j++] = sep;
+ }
+
+ hexCount++;
+ }
+ if (j > 0) {
+ c[j++] = '\n';
+ sb.append(c, 0, j);
+ }
+ // sb.append("\n");
+
+ return sb.toString();
+ }
+
+ public String toHexString(byte[] in, int indentSize, int lineLen) {
+ return toHexString(in, indentSize, lineLen, mSeparator);
+ }
+
+ public String toHexString(byte[] in, int indentSize) {
+ return toHexString(in, indentSize, mLineLen);
+ }
+
+ public String toHexString(byte[] in) {
+ return toHexString(in, mIndentSize);
+ }
+}
diff --git a/base/util/src/netscape/security/util/PrettyPrintResources.java b/base/util/src/netscape/security/util/PrettyPrintResources.java
new file mode 100644
index 000000000..a3f068f64
--- /dev/null
+++ b/base/util/src/netscape/security/util/PrettyPrintResources.java
@@ -0,0 +1,301 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.util.ListResourceBundle;
+
+import netscape.security.extensions.NSCertTypeExtension;
+import netscape.security.x509.KeyUsageExtension;
+
+/**
+ * Resource Boundle for the Pretty Print
+ *
+ * @author Jack Pan-Chen
+ * @version $Revision$, $Date$
+ */
+
+public class PrettyPrintResources extends ListResourceBundle {
+
+ /**
+ * Returns content
+ */
+ public Object[][] getContents() {
+ return contents;
+ }
+
+ /**
+ * Constants. The suffix represents the number of
+ * possible parameters.
+ */
+
+ //certificate pretty print
+ public final static String TOKEN_CERTIFICATE = "tokenCertificate";
+ public final static String TOKEN_DATA = "tokenData";
+ public final static String TOKEN_VERSION = "tokenVersion";
+ public final static String TOKEN_SERIAL = "tokenSerial";
+ public final static String TOKEN_SIGALG = "tokenSignatureAlgorithm";
+ public final static String TOKEN_ISSUER = "tokenIssuer";
+ public final static String TOKEN_VALIDITY = "tokenValidity";
+ public final static String TOKEN_NOT_BEFORE = "tokenNotBefore";
+ public final static String TOKEN_NOT_AFTER = "tokenNotAfter";
+ public final static String TOKEN_SUBJECT = "tokenSubject";
+ public final static String TOKEN_SPKI = "tokenSPKI";
+ public final static String TOKEN_ALGORITHM = "tokenAlgorithm";
+ public final static String TOKEN_PUBLIC_KEY = "tokenPublicKey";
+ public final static String TOKEN_PUBLIC_KEY_MODULUS = "tokenPublicKeyModulus";
+ public final static String TOKEN_PUBLIC_KEY_EXPONENT = "tokenPublicKeyExponent";
+ public final static String TOKEN_EXTENSIONS = "tokenExtensions";
+ public final static String TOKEN_SIGNATURE = "tokenSignature";
+
+ //extension pretty print
+ public final static String TOKEN_YES = "tokenYes";
+ public final static String TOKEN_NO = "tokenNo";
+ public final static String TOKEN_IDENTIFIER = "tokenIdentifier";
+ public final static String TOKEN_CRITICAL = "tokenCritical";
+ public final static String TOKEN_VALUE = "tokenValue";
+
+ //specific extension token
+ public final static String TOKEN_KEY_TYPE = "tokenKeyType";
+ public final static String TOKEN_CERT_TYPE = "tokenCertType";
+ public final static String TOKEN_SKI = "tokenSKI";
+ public final static String TOKEN_AKI = "tokenAKI";
+ public final static String TOKEN_ACCESS_DESC = "tokenAccessDesc";
+ public final static String TOKEN_OCSP_NOCHECK = "tokenOcspNoCheck";
+ public final static String TOKEN_EXTENDED_KEY_USAGE = "tokenExtendedKeyUsage";
+ public final static String TOKEN_PRIVATE_KEY_USAGE = "tokenPrivateKeyUsage";
+ public final static String TOKEN_PRESENCE_SERVER = "tokenPresenceServer";
+ public final static String TOKEN_AIA = "tokenAIA";
+ public final static String TOKEN_CERT_POLICIES = "tokenCertPolicies";
+ public final static String TOKEN_SIA = "tokenSIA";
+ public final static String TOKEN_KEY_USAGE = "tokenKeyUsage";
+ public final static String TOKEN_CERT_USAGE = "tokenCertUsage";
+ public final static String TOKEN_KEY_ID = "tokenKeyId";
+ public final static String TOKEN_AUTH_NAME = "tokenAuthName";
+
+ public final static String TOKEN_CRL = "tokenCRL";
+ public final static String TOKEN_THIS_UPDATE = "tokenThisUpdate";
+ public final static String TOKEN_NEXT_UPDATE = "tokenNextUpdate";
+ public final static String TOKEN_REVOKED_CERTIFICATES = "revokedCerts";
+ public final static String TOKEN_REVOCATION_DATE = "revocationDate";
+
+ public final static String TOKEN_REVOCATION_REASON = "revocationReason";
+ public final static String TOKEN_REASON = "reason";
+
+ public final static String TOKEN_BASIC_CONSTRAINTS = "basicConstraints";
+ public final static String TOKEN_NAME_CONSTRAINTS = "tokenNameConstraints";
+ public final static String TOKEN_NSC_COMMENT = "tokenNSCComment";
+ public final static String TOKEN_IS_CA = "isCA";
+ public final static String TOKEN_PATH_LEN = "pathLen";
+ public final static String TOKEN_PATH_LEN_UNLIMITED = "pathLenUnlimited";
+ public final static String TOKEN_PATH_LEN_UNDEFINED = "pathLenUndefined";
+ public final static String TOKEN_PATH_LEN_INVALID = "pathLenInvalid";
+
+ public final static String TOKEN_CRL_NUMBER = "CRLNumber";
+ public final static String TOKEN_NUMBER = "Number";
+
+ public final static String TOKEN_DELTA_CRL_INDICATOR = "DeltaCRLIndicator";
+ public final static String TOKEN_BASE_CRL_NUMBER = "BaseCRLNumber";
+
+ public final static String TOKEN_CERT_SCOPE_OF_USE = "CertificateScopeOfUse";
+ public final static String TOKEN_SCOPE_OF_USE = "ScopeOfUse";
+ public final static String TOKEN_PORT = "Port";
+
+ public final static String TOKEN_ISSUER_ALT_NAME = "IssuerAlternativeName";
+ public final static String TOKEN_ISSUER_NAMES = "IssuerNames";
+
+ public final static String TOKEN_SUBJECT_ALT_NAME = "SubjectAlternativeName";
+ public final static String TOKEN_SUBJECT_NAME = "SubjectName";
+
+ public final static String TOKEN_DECODING_ERROR = "decodingError";
+
+ public final static String TOKEN_FRESHEST_CRL_EXT = "FreshestCRL";
+ public final static String TOKEN_INHIBIT_ANY_POLICY_EXT = "InhibitAnyPolicy";
+ public final static String TOKEN_SKIP_CERTS = "SkipCerts";
+
+ public final static String TOKEN_CRL_DP_EXT = "CRLDistributionPoints";
+ public final static String TOKEN_CRLDP_NUMPOINTS = "CRLDP_NUMPOINTS";
+ public final static String TOKEN_CRLDP_POINTN = "CRLDP_POINTN";
+ public final static String TOKEN_CRLDP_DISTPOINT = "CRLDP_DISTPOINT";
+ public final static String TOKEN_CRLDP_REASONS = "CRLDP_REASONS";
+ public final static String TOKEN_CRLDP_CRLISSUER = "CRLDP_CRLISSUER";
+
+ public final static String TOKEN_ISSUING_DIST_POINT = "IssuingDistributionPoint";
+ public final static String TOKEN_DIST_POINT_NAME = "DistributionPointName";
+ public final static String TOKEN_FULL_NAME = "FullName";
+ public final static String TOKEN_RELATIVE_NAME = "NameRelativeToCRLIssuer";
+ public final static String TOKEN_ONLY_USER_CERTS = "OnlyContainsUserCerts";
+ public final static String TOKEN_ONLY_CA_CERTS = "OnlyContainsCACerts";
+ public final static String TOKEN_ONLY_SOME_REASONS = "OnlySomeReasons";
+ public final static String TOKEN_INDIRECT_CRL = "IndirectCRL";
+
+ public final static String TOKEN_INVALIDITY_DATE = "invalidityDate";
+ public final static String TOKEN_DATE_OF_INVALIDITY = "dateOfInvalidity";
+
+ public final static String TOKEN_CERTIFICATE_ISSUER = "CertificateIssuer";
+
+ public final static String TOKEN_HOLD_INSTRUCTION = "HoldInstruction";
+ public final static String TOKEN_HOLD_INSTRUCTION_CODE = "HoldInstructionCode";
+ public final static String TOKEN_POLICY_CONSTRAINTS = "PolicyConstraints";
+ public final static String TOKEN_POLICY_MAPPINGS = "PolicyMappings";
+ public final static String TOKEN_SUBJECT_DIR_ATTR = "SubjectDirectoryAttributes";
+
+ // policy constriants extension fields
+ public final static String TOKEN_INHIBIT_POLICY_MAPPING = "inhibitPolicyMapping";
+ public final static String TOKEN_REQUIRE_EXPLICIT_POLICY = "requireExplicitPolicy";
+
+ // policy mappings extension fields
+ public final static String TOKEN_MAPPINGS = "mappings";
+ public final static String TOKEN_MAP = "map";
+ public final static String TOKEN_ISSUER_DOMAIN_POLICY = "issuerDomainPolicy";
+ public final static String TOKEN_SUBJECT_DOMAIN_POLICY = "subjectDomainPolicy";
+
+ // subject directory attribute fields
+ public final static String TOKEN_ATTRIBUTES = "Attributes";
+ public final static String TOKEN_ATTRIBUTE = "Attribute";
+ public final static String TOKEN_VALUES = "Values";
+
+ // field values
+ public final static String TOKEN_NOT_SET = "notSet";
+ public final static String TOKEN_NONE = "none";
+
+ public final static String TOKEN_CACHE_NOT_AVAILABLE = "cacheNotAvailable";
+ public final static String TOKEN_CACHE_IS_EMPTY = "cacheIsEmpty";
+
+ //Tokens should have blank_space as trailer
+ static final Object[][] contents = {
+ { TOKEN_CERTIFICATE, "Certificate: " },
+ { TOKEN_DATA, "Data: " },
+ { TOKEN_VERSION, "Version: " },
+ { TOKEN_SERIAL, "Serial Number: " },
+ { TOKEN_SIGALG, "Signature Algorithm: " },
+ { TOKEN_ISSUER, "Issuer: " },
+ { TOKEN_VALIDITY, "Validity: " },
+ { TOKEN_NOT_BEFORE, "Not Before: " },
+ { TOKEN_NOT_AFTER, "Not After: " },
+ { TOKEN_SUBJECT, "Subject: " },
+ { TOKEN_SPKI, "Subject Public Key Info: " },
+ { TOKEN_ALGORITHM, "Algorithm: " },
+ { TOKEN_PUBLIC_KEY, "Public Key: " },
+ { TOKEN_PUBLIC_KEY_MODULUS, "Public Key Modulus: " },
+ { TOKEN_PUBLIC_KEY_EXPONENT, "Exponent: " },
+ { TOKEN_EXTENSIONS, "Extensions: " },
+ { TOKEN_SIGNATURE, "Signature: " },
+ { TOKEN_YES, "yes " },
+ { TOKEN_NO, "no " },
+ { TOKEN_IDENTIFIER, "Identifier: " },
+ { TOKEN_CRITICAL, "Critical: " },
+ { TOKEN_VALUE, "Value: " },
+ { TOKEN_KEY_TYPE, "Key Type " },
+ { TOKEN_CERT_TYPE, "Netscape Certificate Type " },
+ { TOKEN_SKI, "Subject Key Identifier " },
+ { TOKEN_AKI, "Authority Key Identifier " },
+ { TOKEN_ACCESS_DESC, "Access Description: " },
+ { TOKEN_OCSP_NOCHECK, "OCSP NoCheck: " },
+ { TOKEN_EXTENDED_KEY_USAGE, "Extended Key Usage: " },
+ { TOKEN_PRIVATE_KEY_USAGE, "Private Key Usage: " },
+ { TOKEN_PRESENCE_SERVER, "Presence Server: " },
+ { TOKEN_AIA, "Authority Info Access: " },
+ { TOKEN_CERT_POLICIES, "Certificate Policies: " },
+ { TOKEN_SIA, "Subject Info Access: " },
+ { TOKEN_KEY_USAGE, "Key Usage: " },
+ { KeyUsageExtension.DIGITAL_SIGNATURE, "Digital Signature " },
+ { KeyUsageExtension.NON_REPUDIATION, "Non Repudiation " },
+ { KeyUsageExtension.KEY_ENCIPHERMENT, "Key Encipherment " },
+ { KeyUsageExtension.DATA_ENCIPHERMENT, "Data Encipherment " },
+ { KeyUsageExtension.KEY_AGREEMENT, "Key Agreement " },
+ { KeyUsageExtension.KEY_CERTSIGN, "Key CertSign " },
+ { KeyUsageExtension.CRL_SIGN, "Crl Sign " },
+ { KeyUsageExtension.ENCIPHER_ONLY, "Encipher Only " },
+ { KeyUsageExtension.DECIPHER_ONLY, "Decipher Only " },
+ { TOKEN_CERT_USAGE, "Certificate Usage: " },
+ { NSCertTypeExtension.SSL_CLIENT, "SSL Client " },
+ { NSCertTypeExtension.SSL_SERVER, "SSL Server " },
+ { NSCertTypeExtension.EMAIL, "Secure Email " },
+ { NSCertTypeExtension.OBJECT_SIGNING, "Object Signing " },
+ { NSCertTypeExtension.SSL_CA, "SSL CA " },
+ { NSCertTypeExtension.EMAIL_CA, "Secure Email CA " },
+ { NSCertTypeExtension.OBJECT_SIGNING_CA, "ObjectSigning CA " },
+ { TOKEN_KEY_ID, "Key Identifier: " },
+ { TOKEN_AUTH_NAME, "Authority Name: " },
+ { TOKEN_CRL, "Certificate Revocation List: " },
+ { TOKEN_THIS_UPDATE, "This Update: " },
+ { TOKEN_NEXT_UPDATE, "Next Update: " },
+ { TOKEN_REVOKED_CERTIFICATES, "Revoked Certificates: " },
+ { TOKEN_REVOCATION_DATE, "Revocation Date: " },
+ { TOKEN_REVOCATION_REASON, "Revocation Reason " },
+ { TOKEN_REASON, "Reason: " },
+ { TOKEN_BASIC_CONSTRAINTS, "Basic Constraints " },
+ { TOKEN_NAME_CONSTRAINTS, "Name Constraints " },
+ { TOKEN_NSC_COMMENT, "Netscape Comment " },
+ { TOKEN_IS_CA, "Is CA: " },
+ { TOKEN_PATH_LEN, "Path Length Constraint: " },
+ { TOKEN_PATH_LEN_UNLIMITED, "UNLIMITED" },
+ { TOKEN_PATH_LEN_UNDEFINED, "UNDEFINED" },
+ { TOKEN_PATH_LEN_INVALID, "INVALID" },
+ { TOKEN_CRL_NUMBER, "CRL Number " },
+ { TOKEN_NUMBER, "Number: " },
+ { TOKEN_DELTA_CRL_INDICATOR, "Delta CRL Indicator " },
+ { TOKEN_BASE_CRL_NUMBER, "Base CRL Number: " },
+ { TOKEN_CERT_SCOPE_OF_USE, "Certificate Scope of Use " },
+ { TOKEN_SCOPE_OF_USE, "Scope of Use: " },
+ { TOKEN_PORT, "Port: " },
+ { TOKEN_ISSUER_ALT_NAME, "Issuer Alternative Name " },
+ { TOKEN_ISSUER_NAMES, "Issuer Names: " },
+ { TOKEN_SUBJECT_ALT_NAME, "Subject Alternative Name " },
+ { TOKEN_DECODING_ERROR, "Decoding Error" },
+ { TOKEN_FRESHEST_CRL_EXT, "Freshest CRL " },
+ { TOKEN_INHIBIT_ANY_POLICY_EXT, "Inhibit Any-Policy " },
+ { TOKEN_SKIP_CERTS, "Skip Certs: " },
+ { TOKEN_CRL_DP_EXT, "CRL Distribution Points " },
+ { TOKEN_CRLDP_NUMPOINTS, "Number of Points: " },
+ { TOKEN_CRLDP_POINTN, "Point " },
+ { TOKEN_CRLDP_DISTPOINT, "Distribution Point: " },
+ { TOKEN_CRLDP_REASONS, "Reason Flags: " },
+ { TOKEN_CRLDP_CRLISSUER, "CRL Issuer: " },
+ { TOKEN_ISSUING_DIST_POINT, "Issuing Distribution Point " },
+ { TOKEN_DIST_POINT_NAME, "Distribution Point: " },
+ { TOKEN_FULL_NAME, "Full Name: " },
+ { TOKEN_RELATIVE_NAME, "Name Relative To CRL Issuer: " },
+ { TOKEN_ONLY_USER_CERTS, "Only Contains User Certificates: " },
+ { TOKEN_ONLY_CA_CERTS, "Only Contains CA Certificates: " },
+ { TOKEN_ONLY_SOME_REASONS, "Only Some Reasons: " },
+ { TOKEN_INDIRECT_CRL, "Indirect CRL: " },
+ { TOKEN_INVALIDITY_DATE, "Invalidity Date " },
+ { TOKEN_DATE_OF_INVALIDITY, "Invalidity Date: " },
+ { TOKEN_CERTIFICATE_ISSUER, "Certificate Issuer " },
+ { TOKEN_HOLD_INSTRUCTION, "Hold Instruction Code " },
+ { TOKEN_HOLD_INSTRUCTION_CODE, "Hold Instruction Code: " },
+ { TOKEN_POLICY_CONSTRAINTS, "Policy Constraints " },
+ { TOKEN_INHIBIT_POLICY_MAPPING, "Inhibit Policy Mapping: " },
+ { TOKEN_REQUIRE_EXPLICIT_POLICY, "Require Explicit Policy: " },
+ { TOKEN_POLICY_MAPPINGS, "Policy Mappings " },
+ { TOKEN_MAPPINGS, "Mappings: " },
+ { TOKEN_MAP, "Map " },
+ { TOKEN_ISSUER_DOMAIN_POLICY, "Issuer Domain Policy: " },
+ { TOKEN_SUBJECT_DOMAIN_POLICY, "Subject Domain Policy: " },
+ { TOKEN_SUBJECT_DIR_ATTR, "Subject Directory Attributes " },
+ { TOKEN_ATTRIBUTES, "Attributes:" },
+ { TOKEN_ATTRIBUTE, "Attribute " },
+ { TOKEN_VALUES, "Values: " },
+ { TOKEN_NOT_SET, "not set" },
+ { TOKEN_NONE, "none" },
+ { TOKEN_CACHE_NOT_AVAILABLE, "CRL cache is not available. " },
+ { TOKEN_CACHE_IS_EMPTY, "CRL cache is empty. " },
+ };
+
+}
diff --git a/base/util/src/netscape/security/util/PrintableCharset.java b/base/util/src/netscape/security/util/PrintableCharset.java
new file mode 100644
index 000000000..a9cf15c04
--- /dev/null
+++ b/base/util/src/netscape/security/util/PrintableCharset.java
@@ -0,0 +1,46 @@
+package netscape.security.util;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+public class PrintableCharset extends Charset {
+
+ public PrintableCharset() {
+ super("ASN.1-Printable", null);
+ }
+
+ public static boolean isPrintableChar(char c) {
+ if ((c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z') &&
+ (c < '0' || c > '9') &&
+ (c != ' ') &&
+ (c != '\'') &&
+ (c != '(') &&
+ (c != ')') &&
+ (c != '+') &&
+ (c != ',') &&
+ (c != '-') &&
+ (c != '.') &&
+ (c != '/') &&
+ (c != ':') &&
+ (c != '=') &&
+ (c != '?')) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public boolean contains(Charset cs) {
+ return false;
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new PrintableCharsetDecoder(this);
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new PrintableCharsetEncoder(this);
+ }
+}
diff --git a/base/util/src/netscape/security/util/PrintableCharsetDecoder.java b/base/util/src/netscape/security/util/PrintableCharsetDecoder.java
new file mode 100644
index 000000000..014095494
--- /dev/null
+++ b/base/util/src/netscape/security/util/PrintableCharsetDecoder.java
@@ -0,0 +1,69 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Converts bytes in ASN.1 PrintableString character set to PrintableString
+ * characters.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class PrintableCharsetDecoder extends CharsetDecoder {
+
+ public PrintableCharsetDecoder(Charset cs) {
+ super(cs, 1, 1);
+ }
+
+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+
+ while (true) {
+
+ if (in.remaining() < 1)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ byte b = in.get();
+ char c = (char) (b & 0x7f);
+
+ if (CodingErrorAction.REPORT == unmappableCharacterAction() &&
+ !PrintableCharset.isPrintableChar(c)) {
+ /*
+ "bug" fix for 359010
+ return CoderResult.unmappableForLength(1);
+ */
+ continue;
+ }
+
+ if (out.remaining() < 1) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put(c);
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/util/PrintableCharsetEncoder.java b/base/util/src/netscape/security/util/PrintableCharsetEncoder.java
new file mode 100644
index 000000000..bc658096a
--- /dev/null
+++ b/base/util/src/netscape/security/util/PrintableCharsetEncoder.java
@@ -0,0 +1,71 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Converts characters in ASN.1 PrintableString character set to PrintableString
+ * bytes.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class PrintableCharsetEncoder extends CharsetEncoder {
+
+ public PrintableCharsetEncoder(Charset cs) {
+ super(cs, 1, 1);
+ }
+
+ /*
+ * Converts an array of Unicode characters into an array of PrintableString
+ * bytes and returns the conversion result.
+ * @param in input character buffer to convert.
+ * @param out byte buffer to store output.
+ * @return encoding result.
+ */
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+
+ while (true) {
+
+ if (in.remaining() < 1)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ char c = in.get();
+
+ if (CodingErrorAction.REPORT == unmappableCharacterAction() &&
+ !PrintableCharset.isPrintableChar(c)) {
+ return CoderResult.unmappableForLength(1);
+ }
+
+ if (out.remaining() < 1) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put((byte) (c & 0x7f));
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/util/PubKeyPrettyPrint.java b/base/util/src/netscape/security/util/PubKeyPrettyPrint.java
new file mode 100644
index 000000000..46c007cd9
--- /dev/null
+++ b/base/util/src/netscape/security/util/PubKeyPrettyPrint.java
@@ -0,0 +1,121 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.security.PublicKey;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import netscape.security.provider.RSAPublicKey;
+import netscape.security.x509.X509Key;
+
+/**
+ * This class will display the certificate content in predefined
+ * format.
+ *
+ * @author Jack Pan-Chen
+ * @author Andrew Wnuk
+ * @version $Revision$, $Date$
+ */
+public class PubKeyPrettyPrint {
+
+ /*==========================================================
+ * variables
+ *==========================================================*/
+ private X509Key mX509Key = null;
+ private PrettyPrintFormat pp = null;
+
+ /*==========================================================
+ * constructors
+ *==========================================================*/
+
+ public PubKeyPrettyPrint(PublicKey key) {
+ if (key instanceof X509Key)
+ mX509Key = (X509Key) key;
+
+ pp = new PrettyPrintFormat(":");
+ }
+
+ /*==========================================================
+ * public methods
+ *==========================================================*/
+
+ /**
+ * This method return string representation of the certificate
+ * in predefined format using specified client local. I18N Support.
+ *
+ * @param clientLocale Locale to be used for localization
+ * @return string representation of the certificate
+ */
+ public String toString(Locale clientLocale, int indentSize, int lineLen) {
+
+ if (mX509Key != null)
+ return X509toString(clientLocale, indentSize, lineLen);
+ else
+ return null;
+ }
+
+ public String X509toString(Locale clientLocale, int indentSize, int lineLen) {
+
+ //get I18N resources
+ ResourceBundle resource = ResourceBundle.getBundle(
+ PrettyPrintResources.class.getName());
+
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ String alg = mX509Key.getAlgorithm();
+
+ //XXX I18N Algorithm Name ?
+ sb.append(pp.indent(indentSize) + resource.getString(
+ PrettyPrintResources.TOKEN_ALGORITHM) +
+ alg + " - " +
+ mX509Key.getAlgorithmId().getOID().toString() + "\n");
+
+ if (alg.equals("RSA")) {
+
+ RSAPublicKey rsakey = new RSAPublicKey(mX509Key.getEncoded());
+
+ sb.append(pp.indent(indentSize) + resource.getString(
+ PrettyPrintResources.TOKEN_PUBLIC_KEY) + "\n");
+ sb.append(pp.indent(indentSize + 4) + resource.getString(
+ PrettyPrintResources.TOKEN_PUBLIC_KEY_EXPONENT) +
+ rsakey.getPublicExponent().toInt() + "\n");
+ sb.append(pp.indent(indentSize + 4) + resource.getString(
+ PrettyPrintResources.TOKEN_PUBLIC_KEY_MODULUS) +
+ "(" + rsakey.getKeySize() + " bits) :\n");
+ sb.append(pp.toHexString(
+ rsakey.getModulus().toByteArray(),
+ indentSize + 8, lineLen));
+ } else {
+
+ // DSAPublicKey is more complicated to decode, since
+ // the DSAParams (PQG) is not fully decoded.
+ // So, we just print the entire public key blob
+
+ sb.append(pp.indent(indentSize) + resource.getString(
+ PrettyPrintResources.TOKEN_PUBLIC_KEY) + "\n");
+ sb.append(pp.toHexString(mX509Key.getKey(), indentSize + 4, lineLen));
+ }
+
+ } catch (Exception e) {
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/base/util/src/netscape/security/util/UniversalCharset.java b/base/util/src/netscape/security/util/UniversalCharset.java
new file mode 100644
index 000000000..59cc3c6f4
--- /dev/null
+++ b/base/util/src/netscape/security/util/UniversalCharset.java
@@ -0,0 +1,24 @@
+package netscape.security.util;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+public class UniversalCharset extends Charset {
+
+ public UniversalCharset() {
+ super("ASN.1-Universal", null);
+ }
+
+ public boolean contains(Charset cs) {
+ return false;
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new UniversalCharsetDecoder(this);
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new UniversalCharsetEncoder(this);
+ }
+}
diff --git a/base/util/src/netscape/security/util/UniversalCharsetDecoder.java b/base/util/src/netscape/security/util/UniversalCharsetDecoder.java
new file mode 100644
index 000000000..a41c5ad50
--- /dev/null
+++ b/base/util/src/netscape/security/util/UniversalCharsetDecoder.java
@@ -0,0 +1,98 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Converts bytes in ASN.1 UniversalString character set to UniversalString
+ * characters.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class UniversalCharsetDecoder extends CharsetDecoder {
+
+ public UniversalCharsetDecoder(Charset cs) {
+ super(cs, 0.25f, 1);
+ }
+
+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+
+ while (true) {
+ // XXX we do not know what to do with truly UCS-4 characters here
+ // we also assumed network byte order
+
+ if (in.remaining() < 4)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ byte b0 = in.get();
+ byte b1 = in.get();
+ byte b2 = in.get();
+ byte b3 = in.get();
+
+ if (CodingErrorAction.REPORT == unmappableCharacterAction() &&
+ !((b0 == 0 && b1 == 0) || (b2 == 0 && b3 == 0))) {
+ return CoderResult.unmappableForLength(4);
+ }
+
+ char c;
+ if (b2 == 0 && b3 == 0) {
+ // Try to be a bit forgiving. If the byte order is
+ // reversed, we still try handle it.
+
+ // Sample Date Set (1):
+ // 0000000 f 0 \0 \0 213 0 \0 \0 S 0 \0 \0
+ // 0000014
+
+ // Sample Date Set (2):
+ // 0000000 w \0 \0 \0 w \0 \0 \0 w \0 \0 \0 . \0 \0 \0
+ // 0000020 ( \0 \0 \0 t \0 \0 \0 o \0 \0 \0 b \0 \0 \0
+ // 0000040 e \0 \0 \0 | \0 \0 \0 n \0 \0 \0 o \0 \0 \0
+ // 0000060 t \0 \0 \0 t \0 \0 \0 o \0 \0 \0 b \0 \0 \0
+ // 0000100 e \0 \0 \0 ) \0 \0 \0 . \0 \0 \0 c \0 \0 \0
+ // 0000120 o \0 \0 \0 m \0 \0 \0
+ // 0000130
+ c = (char) (((b1 << 8) & 0xff00) + (b0 & 0x00ff));
+
+ } else { // (b0 == 0 && b1 == 0)
+ // This should be the right order.
+ //
+ // 0000000 0000 00c4 0000 0064 0000 006d 0000 0069
+ // 0000020 0000 006e 0000 0020 0000 0051 0000 0041
+ // 0000040
+
+ c = (char) (((b2 << 8) & 0xff00) + (b3 & 0x00ff));
+ }
+
+ if (out.remaining() < 1) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put(c);
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/util/UniversalCharsetEncoder.java b/base/util/src/netscape/security/util/UniversalCharsetEncoder.java
new file mode 100644
index 000000000..cd2a51296
--- /dev/null
+++ b/base/util/src/netscape/security/util/UniversalCharsetEncoder.java
@@ -0,0 +1,68 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+
+/**
+ * Converts characters in ASN.1 UniversalString character set to UniversalString
+ * bytes.
+ *
+ * @author Lily Hsiao
+ * @author Slava Galperin
+ */
+
+public class UniversalCharsetEncoder extends CharsetEncoder {
+
+ public UniversalCharsetEncoder(Charset cs) {
+ super(cs, 4, 4, new byte[] { 0, 0, 0, 0 });
+ }
+
+ /*
+ * Converts an array of Unicode characters into an array of UniversalString
+ * bytes and returns the conversion result.
+ * @param in input character buffer to convert.
+ * @param out byte buffer to store output.
+ * @return encoding result.
+ */
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+
+ while (true) {
+
+ if (in.remaining() < 1)
+ return CoderResult.UNDERFLOW;
+
+ in.mark();
+ char c = in.get();
+
+ if (out.remaining() < 4) {
+ in.reset();
+ return CoderResult.OVERFLOW;
+ }
+
+ out.put((byte) 0);
+ out.put((byte) 0);
+ out.put((byte) ((c >> 8) & 0xff));
+ out.put((byte) (c & 0xff));
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/ACertAttrSet.java b/base/util/src/netscape/security/x509/ACertAttrSet.java
new file mode 100755
index 000000000..8a757d7f5
--- /dev/null
+++ b/base/util/src/netscape/security/x509/ACertAttrSet.java
@@ -0,0 +1,141 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * A plain certattr set used by pkcs10 to parse an unknown attribute.
+ *
+ * @author Lily Hsiao
+ */
+public class ACertAttrSet implements CertAttrSet {
+
+ protected DerValue mDerValue = null;
+
+ public ACertAttrSet(DerValue derValue) throws IOException {
+ mDerValue = derValue;
+ }
+
+ public DerValue getDerValue() {
+ return mDerValue;
+ }
+
+ /**
+ * Returns a short string describing this certificate attribute.
+ *
+ * @return value of this certificate attribute in
+ * printable form.
+ */
+ public String toString() {
+ return "ACertAttrSet value " + (mDerValue == null ? "null" : "not null");
+ }
+
+ /**
+ * Encodes the attribute to the output stream in a format
+ * that can be parsed by the <code>decode</code> method.
+ *
+ * @param out the OutputStream to encode the attribute to.
+ *
+ * @exception CertificateException on encoding or validity errors.
+ * @exception IOException on other errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ mDerValue.encode((DerOutputStream) out);
+ }
+
+ /**
+ * Decodes the attribute in the input stream.
+ *
+ * @param in the InputStream to read the encoded attribute from.
+ *
+ * @exception CertificateException on decoding or validity errors.
+ * @exception IOException on other errors.
+ */
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ throw new IOException("not supported");
+ }
+
+ /**
+ * Sets an attribute value within this CertAttrSet.
+ *
+ * @param name the name of the attribute (e.g. "x509.info.key")
+ * @param obj the attribute object.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ throw new IOException("not supported");
+ }
+
+ /**
+ * Gets an attribute value for this CertAttrSet.
+ *
+ * @param name the name of the attribute to return.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ public Object get(String name)
+ throws CertificateException, IOException {
+ throw new IOException("not supported");
+ }
+
+ /**
+ * Deletes an attribute value from this CertAttrSet.
+ *
+ * @param name the name of the attribute to delete.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ public void delete(String name)
+ throws CertificateException, IOException {
+ throw new IOException("not supported");
+ }
+
+ /**
+ * Returns an enumeration of the names of the attributes existing within
+ * this attribute.
+ *
+ * @return an enumeration of the attribute names.
+ */
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ /**
+ * Returns the name (identifier) of this CertAttrSet.
+ *
+ * @return the name of this CertAttrSet.
+ */
+ public String getName() {
+ return "Generic Extension";
+ }
+}
diff --git a/base/util/src/netscape/security/x509/AVA.java b/base/util/src/netscape/security/x509/AVA.java
new file mode 100644
index 000000000..ad94c2c61
--- /dev/null
+++ b/base/util/src/netscape/security/x509/AVA.java
@@ -0,0 +1,301 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.UnsupportedCharsetException;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * X.500 Attribute-Value-Assertion (AVA): an attribute, as identified by
+ * some attribute ID, has some particular value. Values are as a rule ASN.1
+ * printable strings. A conventional set of type IDs is recognized when
+ * parsing (and generating) RFC 1779 syntax strings.
+ *
+ * <P>
+ * AVAs are components of X.500 relative names. Think of them as being individual fields of a database record. The
+ * attribute ID is how you identify the field, and the value is part of a particular record.
+ *
+ * @see X500Name
+ * @see RDN
+ * @see LdapDNStrConverter
+ *
+ * @version 1.14
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+// public ... when RDN is public and X.500Names can be
+// constructed using RDNs, and all three classes are cleaner
+public final class AVA implements DerEncoder {
+ ObjectIdentifier oid;
+ DerValue value;
+
+ /**
+ * Constructs an AVA from a Ldap DN string with one AVA component
+ * using the global default LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @param avaString a Ldap DN string with one AVA component.
+ */
+ public AVA(String avaString)
+ throws IOException {
+ AVA ava;
+ ava = LdapDNStrConverter.getDefault().parseAVA(avaString);
+ oid = ava.getOid();
+ value = ava.getValue();
+ }
+
+ /**
+ * Like AVA(String) with a DER encoding order given for Directory Strings.
+ */
+ public AVA(String avaString, byte[] tags)
+ throws IOException {
+ AVA ava;
+ ava = LdapDNStrConverter.getDefault().parseAVA(avaString, tags);
+ oid = ava.getOid();
+ value = ava.getValue();
+ }
+
+ /**
+ * Constructs an AVA from a Ldap DN string containing one AVA
+ * component using the specified LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @param avaString a Ldap DN string containing one AVA.
+ * @param ldapDNStrConverter a LdapDNStrConverter
+ */
+ public AVA(String avaString, LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ AVA ava;
+ ava = ldapDNStrConverter.parseAVA(avaString);
+ oid = ava.getOid();
+ value = ava.getValue();
+ }
+
+ /**
+ * Constructs an AVA from an OID and DerValue.
+ *
+ * @param type an ObjectIdentifier
+ * @param val a DerValue
+ */
+ public AVA(ObjectIdentifier type, DerValue val)
+ throws IOException {
+ oid = type;
+ value = val;
+ }
+
+ /**
+ * Constructs an AVA from an input stream of UTF8 bytes that form
+ * a Ldap DN string. Then parse the Ldap DN string using the global
+ * default LdapDNStrConverter. <br>
+ * Parses an RFC 1779 style AVA string: CN=fee fie foe fum
+ * or perhaps with quotes. Not all defined AVA tags are supported;
+ * of current note are X.400 related ones (PRMD, ADMD, etc).
+ *
+ * This terminates at unescaped AVA separators ("+") or RDN
+ * separators (",", ";"), or DN terminators (">"), and removes
+ * cosmetic whitespace at the end of values.
+ *
+ * @see LdapDNStrConverter
+ * @param in the input stream.
+ */
+ public AVA(InputStream in) throws IOException {
+ try {
+ // convert from UTF8 bytes to java string then parse it.
+ byte[] buffer = new byte[in.available()];
+ in.read(buffer);
+
+ Charset charset = Charset.forName("UTF-8");
+ CharsetDecoder decoder = charset.newDecoder();
+
+ CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(buffer));
+
+ AVA a = LdapDNStrConverter.getDefault().parseAVA(charBuffer.toString());
+ oid = a.getOid();
+ value = a.getValue();
+
+ } catch (UnsupportedCharsetException e) {
+ throw new IOException("UTF8 encoding not supported", e);
+ }
+ }
+
+ /**
+ * Constructs an AVA from a Der Input Stream.
+ *
+ * @param in the Der Input Stream.
+ */
+ public AVA(DerInputStream in) throws IOException {
+ DerValue assertion = in.getDerValue();
+
+ /*
+ * Individual attribute value assertions are SEQUENCE of two values.
+ * That'd be a "struct" outside of ASN.1.
+ */
+ if (assertion.tag != DerValue.tag_Sequence)
+ throw new CertParseError("X500 AVA, not a sequence");
+
+ ObjectIdentifier o = assertion.data.getOID();
+ oid = X500NameAttrMap.getDefault().getOid(o);
+ if (oid == null) {
+ // NSCP #329837
+ // if this OID is not recongized in our map (table),
+ // it is fine. we just store it as regular OID.
+ oid = o;
+ }
+ value = assertion.data.getDerValue();
+
+ if (assertion.data.available() != 0)
+ throw new CertParseError("AVA, extra bytes = "
+ + assertion.data.available());
+ }
+
+ // other public methods.
+
+ /**
+ * Returns true if another AVA has the same OID and DerValue.
+ *
+ * @param other the other AVA.
+ * @return ture iff other AVA has same oid and value.
+ */
+ public boolean equals(AVA other) {
+ return oid.equals(other.oid) && value.equals(other.value);
+ }
+
+ /**
+ * Compares the AVA with an Object, returns true if the object is
+ * an AVA and has the same OID and value.
+ *
+ * @param other the other object.
+ * @return true iff other object is an AVA and has same oid and value.
+ */
+ public boolean equals(Object other) {
+ if (other instanceof AVA)
+ return equals((AVA) other);
+ else
+ return false;
+ }
+
+ /**
+ * Encodes the AVA to a Der output stream.
+ * AVAs are encoded as a SEQUENCE of two elements.
+ *
+ * @param out The Der output stream.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ derEncode(out);
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream tmp2 = new DerOutputStream();
+
+ tmp.putOID(oid);
+ value.encode(tmp);
+ tmp2.write(DerValue.tag_Sequence, tmp);
+ out.write(tmp2.toByteArray());
+ }
+
+ /**
+ * Returns a Ldap DN string with one AVA component using
+ * the global default LdapDNStrConverter.
+ *
+ * @return a Ldap DN string
+ * @exception IOException if an error occurs during conversion.
+ * @see LdapDNStrConverter
+ */
+ public String toLdapDNString()
+ throws IOException {
+ LdapDNStrConverter v = LdapDNStrConverter.getDefault();
+ return v.encodeAVA(this);
+ }
+
+ /**
+ * Returns a Ldap DN string with one AVA component using the specified
+ * LdapDNStrConverter.
+ *
+ * @return a Ldap DN string
+ * @param ldapDNStrConverter a Ldap DN String Converter
+ * @exception IOException if an error occurs during the conversion.
+ * @see LdapDNStrConverter
+ */
+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ return ldapDNStrConverter.encodeAVA(this);
+ }
+
+ /**
+ * Returns a Ldap DN string with the AVA component using the global
+ * default LdapDNStrConverter, or null if an error occurs in conversion.
+ *
+ * @return a Ldap DN string containing the AVA, or null if an
+ * error occurs in the conversion.
+ */
+ public String toString() {
+ String s;
+ try {
+ // NOTE that a LdapDNString is returned here to match the
+ // original source from sun. Could also return the raw value
+ // (before Ldap escaping) here.
+ s = toLdapDNString();
+ } catch (IOException e) {
+ return null;
+ }
+ return s;
+ }
+
+ /**
+ * Returns the OID in the AVA.
+ *
+ * @return the ObjectIdentifier in this AVA.
+ */
+ public ObjectIdentifier getOid() {
+ return oid;
+ }
+
+ /**
+ * Returns the value in this AVA as a DerValue
+ *
+ * @return attribute value in this AVA.
+ */
+ public DerValue getValue() {
+ return value;
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/AVAValueConverter.java b/base/util/src/netscape/security/x509/AVAValueConverter.java
new file mode 100644
index 000000000..cd3ce7616
--- /dev/null
+++ b/base/util/src/netscape/security/x509/AVAValueConverter.java
@@ -0,0 +1,86 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerValue;
+
+/**
+ * Interface for classes that convert a attribute value string to a
+ * DER encoded ASN.1 value and vice versa.
+ * The converters are associated with attribute types, such as
+ * directory string, ia5string, etc.
+ *
+ * <P>
+ * For example, to convert a string, such as an organization name for the "O" attribute to a DerValue, the "O" attribute
+ * is mapped to the DirStrConverter which is used to convert the organization name to a DER encoded Directory String
+ * which is a DerValue of a ASN.1 PrintableString, T.61String or UniversalString for the organization name.
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public interface AVAValueConverter {
+ /**
+ * Converts a string to a DER encoded attribute value.
+ *
+ * @param valueString An AVA value string not encoded in any form.
+ *
+ * @return A DerValue object.
+ *
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public DerValue getValue(String valueString)
+ throws IOException;
+
+ /**
+ * Converts a string to a DER encoded attribute value.
+ * Specify the order of DER tags to use if more than one encoding is
+ * possible. Currently Directory Strings can have different order
+ * for backwards compatibility. By 2003 all should be UTF8String.
+ *
+ * @param valueString An AVA value string not encoded in any form.
+ *
+ * @return A DerValue object.
+ *
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public DerValue getValue(String valueString, byte[] tags)
+ throws IOException;
+
+ /**
+ * Converts a BER encoded value to a DER encoded attribute value.
+ *
+ * @param berStream A byte array of the BER encoded AVA value.
+ * @return A DerValue object.
+ */
+ public DerValue getValue(byte[] berStream)
+ throws IOException;
+
+ /**
+ * Converts a DER encoded value to a string, not encoded in any form.
+ *
+ * @param avaValue A DerValue object.
+ *
+ * @return A string for the value or null if it can't be converted.
+ *
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public String getAsString(DerValue avaValue)
+ throws IOException;
+}
diff --git a/base/util/src/netscape/security/x509/AlgIdDSA.java b/base/util/src/netscape/security/x509/AlgIdDSA.java
new file mode 100644
index 000000000..0a64ad37b
--- /dev/null
+++ b/base/util/src/netscape/security/x509/AlgIdDSA.java
@@ -0,0 +1,185 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.ProviderException;
+import java.security.interfaces.DSAParams;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class identifies DSS/DSA Algorithm variants, which are distinguished
+ * by using different algorithm parameters <em>P, Q, G</em>. It uses the
+ * NIST/IETF standard DER encoding. These are used to implement the Digital
+ * Signature Standard (DSS), FIPS 186.
+ *
+ * <P>
+ * <em><b>NOTE:</b> At this time, DSS/DSA Algorithm IDs must always
+ * include these parameters. Use of DSS/DSA in modes where parameters are
+ * either implicit (e.g. a default applicable to a site or a larger scope),
+ * or are derived from some Certificate Authority's DSS certificate, is
+ * not currently supported. </em>
+ *
+ * @version 1.31
+ * @author David Brownell
+ */
+public final class AlgIdDSA extends AlgorithmId implements DSAParams {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5978220691806461631L;
+ /*
+ * The three unsigned integer parameters.
+ */
+ private BigInteger p, q, g;
+
+ /** Returns the DSS/DSA parameter "P" */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /** Returns the DSS/DSA parameter "Q" */
+ public BigInteger getQ() {
+ return q;
+ }
+
+ /** Returns the DSS/DSA parameter "G" */
+ public BigInteger getG() {
+ return g;
+ }
+
+ /**
+ * Default constructor. The OID and parameters must be
+ * deserialized before this algorithm ID is used.
+ */
+ // XXX deprecated for general use
+ public AlgIdDSA() {
+ }
+
+ AlgIdDSA(DerValue val) throws IOException {
+ super(val.getOID());
+ }
+
+ /**
+ * Construct an AlgIdDSA from an X.509 encoded byte array.
+ */
+ public AlgIdDSA(byte[] encodedAlg) throws IOException {
+ super(new DerValue(encodedAlg).getOID());
+ }
+
+ /**
+ * Constructs a DSS/DSA Algorithm ID from unsigned integers that
+ * define the algorithm parameters. Those integers are encoded
+ * as big-endian byte arrays.
+ *
+ * @param p the DSS/DSA paramter "P"
+ * @param q the DSS/DSA paramter "Q"
+ * @param g the DSS/DSA paramter "G"
+ */
+ public AlgIdDSA(byte p[], byte q[], byte g[])
+ throws IOException {
+ this(new BigInteger(1, p),
+ new BigInteger(1, q),
+ new BigInteger(1, g));
+ }
+
+ /**
+ * Constructs a DSS/DSA Algorithm ID from numeric parameters.
+ *
+ * @param p the DSS/DSA paramter "P"
+ * @param q the DSS/DSA paramter "Q"
+ * @param g the DSS/DSA paramter "G"
+ */
+ public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) {
+ super(DSA_oid);
+
+ try {
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ initializeParams();
+
+ } catch (IOException e) {
+ /* this should not happen */
+ throw new ProviderException("Construct DSS/DSA Algorithm ID");
+ }
+ }
+
+ /**
+ * Returns "DSA", indicating the Digital Signature Algorithm (DSA) as
+ * defined by the Digital Signature Standard (DSS), FIPS 186.
+ */
+ public String getName() {
+ return "DSA";
+ }
+
+ /*
+ * For algorithm IDs which haven't been created from a DER encoded
+ * value, "params" must be created.
+ */
+ private void initializeParams()
+ throws IOException {
+ DerOutputStream out = new DerOutputStream();
+
+ out.putInteger(new BigInt(p.toByteArray()));
+ out.putInteger(new BigInt(q.toByteArray()));
+ out.putInteger(new BigInt(g.toByteArray()));
+ params = new DerValue(DerValue.tag_Sequence, out.toByteArray());
+ }
+
+ /**
+ * Parses algorithm parameters P, Q, and G. They're found
+ * in the "params" member, which never needs to be changed.
+ */
+ protected void decodeParams()
+ throws IOException {
+ if (params == null || params.tag != DerValue.tag_Sequence)
+ throw new IOException("DSA alg parsing error");
+
+ params.data.reset();
+
+ this.p = params.data.getInteger().toBigInteger();
+ this.q = params.data.getInteger().toBigInteger();
+ this.g = params.data.getInteger().toBigInteger();
+
+ if (params.data.available() != 0)
+ throw new IOException("AlgIdDSA params, extra=" +
+ params.data.available());
+ }
+
+ /*
+ * Returns a formatted string describing the parameters.
+ */
+ public String toString() {
+ return paramsToString();
+ }
+
+ /*
+ * Returns a string describing the parameters.
+ */
+ protected String paramsToString() {
+ return "\n p:\n" + (new BigInt(p)).toString() +
+ "\n q:\n" + (new BigInt(q)).toString() +
+ "\n g:\n" + (new BigInt(g)).toString() +
+ "\n";
+ }
+}
diff --git a/base/util/src/netscape/security/x509/AlgorithmId.java b/base/util/src/netscape/security/x509/AlgorithmId.java
new file mode 100644
index 000000000..b0113af41
--- /dev/null
+++ b/base/util/src/netscape/security/x509/AlgorithmId.java
@@ -0,0 +1,767 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * This class identifies algorithms, such as cryptographic transforms, each
+ * of which may be associated with parameters. Instances of this base class
+ * are used when this runtime environment has no special knowledge of the
+ * algorithm type, and may also be used in other cases. Equivalence is
+ * defined according to OID and (where relevant) parameters.
+ *
+ * <P>
+ * Subclasses may be used, for example when when the algorithm ID has associated parameters which some code (e.g. code
+ * using public keys) needs to have parsed. Two examples of such algorithms are Diffie-Hellman key exchange, and the
+ * Digital Signature Standard Algorithm (DSS/DSA).
+ *
+ * <P>
+ * The OID constants defined in this class correspond to some widely used algorithms, for which conventional string
+ * names have been defined. This class is not a general repository for OIDs, or for such string names. Note that the
+ * mappings between algorithm IDs and algorithm names is not one-to-one.
+ *
+ * @version 1.70
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class AlgorithmId implements Serializable, DerEncoder {
+
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = 7205873507486557157L;
+
+ /* Are we debugging? */
+ private static boolean debug = false;
+
+ /**
+ * The object identitifer being used for this algorithm.
+ */
+ private ObjectIdentifier algid = null;
+
+ // The (parsed) parameters
+ private AlgorithmParameters algParams;
+
+ /**
+ * Parameters for this algorithm. These are stored in unparsed
+ * DER-encoded form; subclasses can be made to automaticaly parse
+ * them so there is fast access to these parameters.
+ */
+ protected DerValue params = null;
+
+ protected String paramsString = null;
+
+ /**
+ * Returns one of the algorithm IDs most commonly associated
+ * with this algorithm name.
+ *
+ * @param algname the name being used
+ * @deprecated use the short get form of this method.
+ * @exception NoSuchAlgorithmException on error.
+ */
+ public static AlgorithmId getAlgorithmId(String algname)
+ throws NoSuchAlgorithmException {
+ return get(algname);
+ }
+
+ public AlgorithmParameters getParameters() {
+ return this.algParams;
+ }
+
+ public String getParametersString() {
+ return this.paramsString;
+ }
+
+ public void setParametersString(String paramStr) {
+
+ this.paramsString = paramStr;
+ }
+
+ /**
+ * Returns one of the algorithm IDs most commonly associated
+ * with this algorithm name.
+ *
+ * @param algname the name being used
+ * @exception NoSuchAlgorithmException on error.
+ */
+ public static AlgorithmId get(String algname)
+ throws NoSuchAlgorithmException {
+ ObjectIdentifier oid = algOID(algname);
+
+ if (oid == null)
+ throw new NoSuchAlgorithmException("unrecognized algorithm name: " + algname);
+
+ return new AlgorithmId(oid);
+ }
+
+ /**
+ * Parse (unmarshal) an ID from a DER sequence input value. This form
+ * parsing might be used when expanding a value which has already been
+ * partially unmarshaled as a set or sequence member.
+ *
+ * @exception IOException on error.
+ * @param val the input value, which contains the algid and, if
+ * there are any parameters, those parameters.
+ * @return an ID for the algorithm. If the system is configured
+ * appropriately, this may be an instance of a class
+ * with some kind of special support for this algorithm.
+ * In that case, you may "narrow" the type of the ID.
+ */
+ public static AlgorithmId parse(DerValue val)
+ throws IOException {
+ if (val.tag != DerValue.tag_Sequence)
+ throw new IOException("algid parse error, not a sequence");
+
+ /*
+ * Get the algorithm ID and any parameters.
+ */
+ ObjectIdentifier algid;
+ DerValue params;
+ DerInputStream in = val.toDerInputStream();
+
+ algid = in.getOID();
+ if (in.available() == 0)
+ params = null;
+ else {
+ params = in.getDerValue();
+ if (params.tag == DerValue.tag_Null)
+ params = null;
+ }
+
+ /*
+ * Figure out what class (if any) knows about this oid's
+ * parameters. Make one, and give it the data to decode.
+ */
+ AlgorithmId alg = new AlgorithmId(algid, params);
+ if (params != null)
+ alg.decodeParams();
+
+ /*
+ * Set the raw params string in case
+ * higher level code might want the info
+ */
+
+ String paramStr = null;
+
+ if (params != null) {
+ paramStr = params.toString();
+ }
+
+ alg.setParametersString(paramStr);
+
+ return alg;
+ }
+
+ public static AlgorithmId parse(byte[] val)
+ throws IOException {
+ return null;
+ }
+
+ /**
+ * Constructs a parameterless algorithm ID.
+ *
+ * @param oid the identifier for the algorithm
+ */
+ public AlgorithmId(ObjectIdentifier oid) {
+ algid = oid;
+ }
+
+ private AlgorithmId(ObjectIdentifier oid, DerValue params)
+ throws IOException {
+ this.algid = oid;
+ this.params = params;
+ if (this.params != null)
+ decodeParams();
+ }
+
+ /**
+ * Constructs an algorithm ID which will be initialized
+ * separately, for example by deserialization.
+ *
+ * @deprecated use one of the other constructors.
+ */
+ public AlgorithmId() {
+ }
+
+ protected void decodeParams() throws IOException {
+ try {
+ this.algParams = AlgorithmParameters.getInstance
+ (this.algid.toString());
+ } catch (NoSuchAlgorithmException e) {
+ /*
+ * This algorithm parameter type is not supported, so we cannot
+ * parse the parameters.
+ */
+ this.algParams = null;
+ return;
+ }
+ // Decode (parse) the parameters
+ this.algParams.init(this.params.toByteArray());
+ }
+
+ /**
+ * Marshal a DER-encoded "AlgorithmID" sequence on the DER stream.
+ */
+ public final void encode(DerOutputStream out)
+ throws IOException {
+ derEncode(out);
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ DerOutputStream bytes = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ bytes.putOID(algid);
+ if (params == null)
+ bytes.putNull();
+ else
+ bytes.putDerValue(params);
+ tmp.write(DerValue.tag_Sequence, bytes);
+ out.write(tmp.toByteArray());
+ }
+
+ // XXXX cleaning required
+ /**
+ * Returns the DER-encoded X.509 AlgorithmId as a byte array.
+ */
+ public final byte[] encode() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream bytes = new DerOutputStream();
+
+ bytes.putOID(algid);
+ if (params == null)
+ bytes.putNull();
+ else
+ bytes.putDerValue(params);
+ out.write(DerValue.tag_Sequence, bytes);
+ return out.toByteArray();
+ }
+
+ /**
+ * Returns list of signing algorithms for a key algorithm such as
+ * RSA or DSA.
+ */
+ public static String[] getSigningAlgorithms(AlgorithmId alg) {
+ ObjectIdentifier algOid = alg.getOID();
+ //System.out.println("Key Alg oid "+algOid.toString());
+ if (algOid.equals(DSA_oid) || algOid.equals(DSA_OIW_oid)) {
+ return DSA_SIGNING_ALGORITHMS;
+ } else if (algOid.equals(RSA_oid) || algOid.equals(RSAEncryption_oid)) {
+ return RSA_SIGNING_ALGORITHMS;
+ } else if (algOid.equals(ANSIX962_EC_Public_Key_oid) || algOid.equals(ANSIX962_SHA1_With_EC_oid)) {
+ return EC_SIGNING_ALGORITHMS;
+ } else {
+ return null;
+ }
+ }
+
+ /*
+ * Translates from some common algorithm names to the
+ * OID with which they're usually associated ... this mapping
+ * is the reverse of the one below, except in those cases
+ * where synonyms are supported or where a given algorithm
+ * is commonly associated with multiple OIDs.
+ */
+ private static ObjectIdentifier algOID(String name) {
+ // Digesting algorithms
+
+ if (name.equals("MD5"))
+ return AlgorithmId.MD5_oid;
+ if (name.equals("MD2"))
+ return AlgorithmId.MD2_oid;
+ if (name.equals("SHA") || name.equals("SHA1")
+ || name.equals("SHA-1"))
+ return AlgorithmId.SHA_oid;
+ if (name.equals("SHA256") || name.equals("SHA-256"))
+ return AlgorithmId.SHA256_oid;
+ if (name.equals("SHA512") || name.equals("SHA-512"))
+ return AlgorithmId.SHA512_oid;
+
+ // Various public key algorithms
+
+ if (name.equals("RSA"))
+ return AlgorithmId.RSA_oid;
+
+ if (name.equals("RSAEncryption"))
+ return AlgorithmId.RSAEncryption_oid;
+ if (name.equals("Diffie-Hellman") || name.equals("DH"))
+ return AlgorithmId.DH_oid;
+ if (name.equals("DSA"))
+ return AlgorithmId.DSA_oid;
+
+ // Common signature types
+
+ if (name.equals("SHA1withEC") || name.equals("SHA1/EC")
+ || name.equals("1.2.840.10045.4.1"))
+ return AlgorithmId.sha1WithEC_oid;
+ if (name.equals("SHA256withEC") || name.equals("SHA256/EC")
+ || name.equals("1.2.840.10045.4.3.2"))
+ return AlgorithmId.sha256WithEC_oid;
+ if (name.equals("SHA384withEC") || name.equals("SHA384/EC")
+ || name.equals("1.2.840.10045.4.3.3"))
+ return AlgorithmId.sha384WithEC_oid;
+ if (name.equals("SHA512withEC") || name.equals("SHA512/EC")
+ || name.equals("1.2.840.10045.4.3.4"))
+ return AlgorithmId.sha512WithEC_oid;
+ if (name.equals("SHA1withRSA") || name.equals("SHA1/RSA")
+ || name.equals("1.2.840.113549.1.1.5"))
+ return AlgorithmId.sha1WithRSAEncryption_oid;
+ if (name.equals("SHA256withRSA") || name.equals("SHA256/RSA")
+ || name.equals("1.2.840.113549.1.1.11"))
+ return AlgorithmId.sha256WithRSAEncryption_oid;
+ if (name.equals("SHA512withRSA") || name.equals("SHA512/RSA")
+ || name.equals("1.2.840.113549.1.1.13"))
+ return AlgorithmId.sha512WithRSAEncryption_oid;
+ if (name.equals("MD5withRSA") || name.equals("MD5/RSA"))
+ return AlgorithmId.md5WithRSAEncryption_oid;
+ if (name.equals("MD2withRSA") || name.equals("MD2/RSA"))
+ return AlgorithmId.md2WithRSAEncryption_oid;
+ if (name.equals("SHAwithDSA") || name.equals("SHA1withDSA")
+ || name.equals("SHA/DSA") || name.equals("SHA1/DSA"))
+ return AlgorithmId.sha1WithDSA_oid;
+
+ return null;
+ }
+
+ /*
+ * For the inevitable cases where key or signature types are not
+ * configured in an environment which encounters such keys or
+ * signatures, we still attempt to provide user-friendly names
+ * for some of the most common algorithms. Subclasses can of
+ * course override getName().
+ *
+ * Wherever possible, the names are those defined by the IETF.
+ * Such names are noted below.
+ */
+ private String algName() {
+ // Common message digest algorithms
+
+ if (algid.equals(AlgorithmId.MD5_oid))
+ return "MD5"; // RFC 1423
+ if (algid.equals(AlgorithmId.MD2_oid))
+ return "MD2"; // RFC 1423
+ if (algid.equals(AlgorithmId.SHA_oid))
+ return "SHA";
+ if (algid.equals(AlgorithmId.SHA256_oid))
+ return "SHA256";
+ if (algid.equals(AlgorithmId.SHA512_oid))
+ return "SHA512";
+
+ // Common key types
+
+ if (algid.equals(AlgorithmId.ANSIX962_EC_Public_Key_oid))
+ return "EC";
+ if (algid.equals(AlgorithmId.RSAEncryption_oid)
+ || algid.equals(AlgorithmId.RSA_oid))
+ return "RSA";
+ if (algid.equals(AlgorithmId.DH_oid)
+ || algid.equals(AlgorithmId.DH_PKIX_oid))
+ return "Diffie-Hellman";
+ if (algid.equals(AlgorithmId.DSA_oid)
+ || algid.equals(AlgorithmId.DSA_OIW_oid))
+ return "DSA";
+
+ // Common signature types
+
+ if (algid.equals(AlgorithmId.sha1WithEC_oid))
+ return "SHA1withEC";
+ if (algid.equals(AlgorithmId.sha256WithEC_oid))
+ return "SHA256withEC";
+ if (algid.equals(AlgorithmId.sha384WithEC_oid))
+ return "SHA384withEC";
+ if (algid.equals(AlgorithmId.sha512WithEC_oid))
+ return "SHA512withEC";
+ if (algid.equals(AlgorithmId.md5WithRSAEncryption_oid))
+ return "MD5withRSA";
+ if (algid.equals(AlgorithmId.md2WithRSAEncryption_oid))
+ return "MD2withRSA";
+ if (algid.equals(AlgorithmId.sha1WithRSAEncryption_oid))
+ return "SHA1withRSA";
+ if (algid.equals(AlgorithmId.sha256WithRSAEncryption_oid))
+ return "SHA256withRSA";
+ if (algid.equals(AlgorithmId.sha512WithRSAEncryption_oid))
+ return "SHA512withRSA";
+ if (algid.equals(AlgorithmId.sha1WithDSA_oid)
+ || algid.equals(AlgorithmId.sha1WithDSA_OIW_oid)
+ || algid.equals(AlgorithmId.shaWithDSA_OIW_oid))
+ return "SHA1withDSA";
+
+ // default returns a dot-notation ID
+
+ return "OID." + algid.toString();
+ }
+
+ /**
+ * Returns the ISO OID for this algorithm. This is usually converted
+ * to a string and used as part of an algorithm name, for example
+ * "OID.1.3.14.3.2.13" style notation. Use the <code>getName</code> call when you do not need to ensure cross-system
+ * portability
+ * of algorithm names, or need a user friendly name.
+ */
+ final public ObjectIdentifier getOID() {
+ return algid;
+ }
+
+ /**
+ * Returns a name for the algorithm which may be more intelligible
+ * to humans than the algorithm's OID, but which won't necessarily
+ * be comprehensible on other systems. For example, this might
+ * return a name such as "MD5withRSA" for a signature algorithm on
+ * some systems. It also returns names like "OID.1.2.3.4", when
+ * no particular name for the algorithm is known.
+ */
+ public String getName() {
+ return algName();
+ }
+
+ /**
+ * Returns a string describing the algorithm and its parameters.
+ */
+ public String toString() {
+ return (algName() + paramsToString());
+ }
+
+ /**
+ * Returns the DER encoded parameter, which can then be
+ * used to initialize java.security.AlgorithmParamters.
+ *
+ * @return DER encoded parameters, or null not present.
+ */
+ public byte[] getEncodedParams() throws IOException {
+ if (params == null)
+ return null;
+ else
+ return params.toByteArray();
+ }
+
+ /**
+ * Provides a human-readable description of the algorithm parameters.
+ * This may be redefined by subclasses which parse those parameters.
+ */
+ protected String paramsToString() {
+ if (params == null) {
+ return "";
+ } else if (algParams != null) {
+ return algParams.toString();
+ } else {
+ return ", params unparsed";
+ }
+ }
+
+ /**
+ * Returns true iff the argument indicates the same algorithm
+ * with the same parameters.
+ */
+ public boolean equals(AlgorithmId other) {
+ if (!algid.equals(other.algid))
+ return false;
+ else if (params == null && other.params == null)
+ return true;
+ else if (params == null)
+ return false;
+ else
+ return params.equals(other.params);
+ }
+
+ /**
+ * Compares this AlgorithmID to another. If algorithm parameters are
+ * available, they are compared. Otherwise, just the object IDs
+ * for the algorithm are compared.
+ *
+ * @param other preferably an AlgorithmId, else an ObjectIdentifier
+ */
+ public boolean equals(Object other) {
+ if (other instanceof AlgorithmId)
+ return equals((AlgorithmId) other);
+ else if (other instanceof ObjectIdentifier)
+ return equals((ObjectIdentifier) other);
+ else
+ return false;
+ }
+
+ /**
+ * Compares two algorithm IDs for equality. Returns true iff
+ * they are the same algorithm, ignoring algorithm parameters.
+ */
+ public final boolean equals(ObjectIdentifier id) {
+ return algid.equals(id);
+ }
+
+ /*****************************************************************/
+
+ /*
+ * HASHING ALGORITHMS
+ */
+ private static final int MD2_data[] = { 1, 2, 840, 113549, 2, 2 };
+ private static final int MD5_data[] = { 1, 2, 840, 113549, 2, 5 };
+ // sha = { 1, 3, 14, 3, 2, 18 };
+ private static final int SHA1_OIW_data[] = { 1, 3, 14, 3, 2, 26 };
+ private static final int SHA256_data[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
+ private static final int SHA512_data[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
+
+ /**
+ * Algorithm ID for the MD2 Message Digest Algorthm, from RFC 1319.
+ * OID = 1.2.840.113549.2.2
+ */
+ public static final ObjectIdentifier MD2_oid = new ObjectIdentifier(MD2_data);
+
+ /**
+ * Algorithm ID for the MD5 Message Digest Algorthm, from RFC 1321.
+ * OID = 1.2.840.113549.2.5
+ */
+ public static final ObjectIdentifier MD5_oid = new ObjectIdentifier(MD5_data);
+
+ /**
+ * Algorithm ID for the SHA1 Message Digest Algorithm, from FIPS 180-1.
+ * This is sometimes called "SHA", though that is often confusing since
+ * many people refer to FIPS 180 (which has an error) as defining SHA.
+ * OID = 1.3.14.3.2.26
+ */
+ public static final ObjectIdentifier SHA_oid = new ObjectIdentifier(SHA1_OIW_data);
+
+ public static final ObjectIdentifier SHA256_oid = new ObjectIdentifier(SHA256_data);
+
+ public static final ObjectIdentifier SHA512_oid = new ObjectIdentifier(SHA512_data);
+
+ /*
+ * COMMON PUBLIC KEY TYPES
+ */
+ private static final int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
+ private static final int DH_PKIX_data[] = { 1, 2, 840, 10046, 2, 1 };
+ private static final int DSA_OIW_data[] = { 1, 3, 14, 3, 2, 12 };
+ private static final int DSA_PKIX_data[] = { 1, 2, 840, 10040, 4, 1 };
+ private static final int RSA_data[] = { 1, 2, 5, 8, 1, 1 };
+ private static final int RSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 1 };
+ private static final int ANSI_X962_public_key_data[] =
+ { 1, 2, 840, 10045, 2, 1 };
+ private static final int ANSI_X962_sha1_with_ec_data[] =
+ { 1, 2, 840, 10045, 4, 1 };
+
+ public static final ObjectIdentifier ANSIX962_EC_Public_Key_oid = new ObjectIdentifier(ANSI_X962_public_key_data);
+ public static final ObjectIdentifier ANSIX962_SHA1_With_EC_oid = new ObjectIdentifier(ANSI_X962_sha1_with_ec_data);
+
+ /*
+ * Note the preferred OIDs are named simply with no "OIW" or
+ * "PKIX" in them, even though they may point to data from these
+ * specs; e.g. SHA_oid, DH_oid, DSA_oid, SHA1WithDSA_oid...
+ */
+ /**
+ * Algorithm ID for Diffie Hellman Key agreement, from PKCS #3.
+ * Parameters include public values P and G, and may optionally specify
+ * the length of the private key X. Alternatively, algorithm parameters
+ * may be derived from another source such as a Certificate Authority's
+ * certificate.
+ * OID = 1.2.840.113549.1.3.1
+ */
+ public static final ObjectIdentifier DH_oid = new ObjectIdentifier(DH_data);
+
+ /**
+ * Algorithm ID for the Diffie Hellman Key Agreement (DH), from the
+ * IETF PKIX IPKI Part I.
+ * Parameters may include public values P and G.
+ * OID = 1.2.840.10046.2.1
+ */
+ public static final ObjectIdentifier DH_PKIX_oid = new ObjectIdentifier(DH_PKIX_data);
+
+ /**
+ * Algorithm ID for the Digital Signing Algorithm (DSA), from the
+ * NIST OIW Stable Agreements part 12.
+ * Parameters may include public values P, Q, and G; or these may be
+ * derived from
+ * another source such as a Certificate Authority's certificate.
+ * OID = 1.3.14.3.2.12
+ */
+ public static final ObjectIdentifier DSA_OIW_oid = new ObjectIdentifier(DSA_OIW_data);
+
+ /**
+ * Algorithm ID for the Digital Signing Algorithm (DSA), from the
+ * IETF PKIX IPKI Part I.
+ * Parameters may include public values P, Q, and G; or these may be
+ * derived from
+ * another source such as a Certificate Authority's certificate.
+ * OID = 1.2.840.10040.4.1
+ */
+ public static final ObjectIdentifier DSA_oid = new ObjectIdentifier(DSA_PKIX_data);
+
+ /**
+ * Algorithm ID for RSA keys used for any purpose, as defined in X.509.
+ * The algorithm parameter is a single value, the number of bits in the
+ * public modulus.
+ * OID = 1.2.5.8.1.1
+ */
+ public static final ObjectIdentifier RSA_oid = new ObjectIdentifier(RSA_data);
+
+ /**
+ * Algorithm ID for RSA keys used with RSA encryption, as defined
+ * in PKCS #1. There are no parameters associated with this algorithm.
+ * OID = 1.2.840.113549.1.1.1
+ */
+ public static final ObjectIdentifier RSAEncryption_oid = new ObjectIdentifier(RSAEncryption_data);
+
+ /*
+ * COMMON SIGNATURE ALGORITHMS
+ */
+ private static final int sha1WithEC_data[] =
+ { 1, 2, 840, 10045, 4, 1 };
+ private static final int sha256WithEC_data[] =
+ { 1, 2, 840, 10045, 4, 3, 2 };
+ private static final int sha384WithEC_data[] =
+ { 1, 2, 840, 10045, 4, 3, 3 };
+ private static final int sha512WithEC_data[] =
+ { 1, 2, 840, 10045, 4, 3, 4 };
+ private static final int md2WithRSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 2 };
+ private static final int md5WithRSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 4 };
+ private static final int sha1WithRSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 5 };
+ private static final int sha256WithRSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 11 };
+ private static final int sha512WithRSAEncryption_data[] =
+ { 1, 2, 840, 113549, 1, 1, 13 };
+ private static final int sha1WithRSAEncryption_OIW_data[] =
+ { 1, 3, 14, 3, 2, 29 };
+ private static final int shaWithDSA_OIW_data[] =
+ { 1, 3, 14, 3, 2, 13 };
+ private static final int sha1WithDSA_OIW_data[] =
+ { 1, 3, 14, 3, 2, 27 };
+ private static final int dsaWithSHA1_PKIX_data[] =
+ { 1, 2, 840, 10040, 4, 3 };
+
+ public static final ObjectIdentifier sha1WithEC_oid = new
+ ObjectIdentifier(sha1WithEC_data);
+
+ public static final ObjectIdentifier sha256WithEC_oid = new
+ ObjectIdentifier(sha256WithEC_data);
+
+ public static final ObjectIdentifier sha384WithEC_oid = new
+ ObjectIdentifier(sha384WithEC_data);
+
+ public static final ObjectIdentifier sha512WithEC_oid = new
+ ObjectIdentifier(sha512WithEC_data);
+
+ /**
+ * Identifies a signing algorithm where an MD2 digest is encrypted
+ * using an RSA private key; defined in PKCS #1. Use of this
+ * signing algorithm is discouraged due to MD2 vulnerabilities.
+ * OID = 1.2.840.113549.1.1.2
+ */
+ public static final ObjectIdentifier md2WithRSAEncryption_oid = new
+ ObjectIdentifier(md2WithRSAEncryption_data);
+
+ /**
+ * Identifies a signing algorithm where an MD5 digest is
+ * encrypted using an RSA private key; defined in PKCS #1.
+ * OID = 1.2.840.113549.1.1.4
+ */
+ public static final ObjectIdentifier md5WithRSAEncryption_oid = new
+ ObjectIdentifier(md5WithRSAEncryption_data);
+
+ /**
+ * The proper one for sha1/rsa
+ */
+ public static final ObjectIdentifier sha1WithRSAEncryption_oid = new
+ ObjectIdentifier(sha1WithRSAEncryption_data);
+
+ /**
+ * The proper one for sha256/rsa
+ */
+ public static final ObjectIdentifier sha256WithRSAEncryption_oid = new
+ ObjectIdentifier(sha256WithRSAEncryption_data);
+
+ /**
+ * The proper one for sha512/rsa
+ */
+ public static final ObjectIdentifier sha512WithRSAEncryption_oid = new
+ ObjectIdentifier(sha512WithRSAEncryption_data);
+
+ /**
+ * Identifies a signing algorithm where an SHA1 digest is
+ * encrypted using an RSA private key; defined in NIST OIW.
+ * OID = 1.3.14.3.2.29
+ */
+ public static final ObjectIdentifier sha1WithRSAEncryption_OIW_oid = new
+ ObjectIdentifier(sha1WithRSAEncryption_OIW_data);
+
+ /**
+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
+ * SHA digest is signed using the Digital Signing Algorithm (DSA).
+ * This should not be used.
+ * OID = 1.3.14.3.2.13
+ */
+ public static final ObjectIdentifier shaWithDSA_OIW_oid = new ObjectIdentifier(shaWithDSA_OIW_data);
+
+ /**
+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
+ * SHA1 digest is signed using the Digital Signing Algorithm (DSA).
+ * OID = 1.3.14.3.2.27
+ */
+ public static final ObjectIdentifier sha1WithDSA_OIW_oid = new ObjectIdentifier(sha1WithDSA_OIW_data);
+
+ /**
+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
+ * SHA1 digest is signed using the Digital Signing Algorithm (DSA).
+ * OID = 1.2.840.10040.4.3
+ */
+ public static final ObjectIdentifier sha1WithDSA_oid = new ObjectIdentifier(dsaWithSHA1_PKIX_data);
+
+ /**
+ * Supported signing algorithms for a DSA key.
+ */
+ public static final String[] DSA_SIGNING_ALGORITHMS = new String[]
+ { "SHA1withDSA" };
+
+ /**
+ * Supported signing algorithms for a RSA key.
+ */
+ public static final String[] RSA_SIGNING_ALGORITHMS = new String[]
+ { "SHA1withRSA", "SHA256withRSA", "SHA512withRSA", "MD5withRSA", "MD2withRSA" };
+
+ public static final String[] EC_SIGNING_ALGORITHMS = new String[]
+ { "SHA1withEC", "SHA256withEC", "SHA384withEC", "SHA512withEC" };
+
+ /**
+ * All supported signing algorithms.
+ */
+ public static final String[] ALL_SIGNING_ALGORITHMS = new String[]
+ {
+ "SHA1withRSA", "MD5withRSA", "MD2withRSA", "SHA1withDSA", "SHA256withRSA", "SHA512withRSA", "SHA1withEC",
+ "SHA256withEC", "SHA384withEC", "SHA512withEC" };
+
+}
diff --git a/base/util/src/netscape/security/x509/Attribute.java b/base/util/src/netscape/security/x509/Attribute.java
new file mode 100644
index 000000000..11e22db10
--- /dev/null
+++ b/base/util/src/netscape/security/x509/Attribute.java
@@ -0,0 +1,325 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * An attribute, as identified by some attribute ID, has some particular values.
+ * Values are as a rule ASN.1 printable strings. A conventional set of type IDs
+ * is recognized when parsing. The following shows the syntax:
+ *
+ * <pre>
+ *
+ * Attribute ::= SEQUENCE {
+ * type AttributeType,
+ * value SET OF AttributeValue
+ * -- at least one value is required --}
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY
+ *
+ * </pre>
+ *
+ * Refer to draft-ietf-pkix-ipki-part1-11 for the support attributes listed on
+ * page 96 of the internet draft. The are listed here for easy reference: name,
+ * common name, surname, given name, initials, generation qualifier, dn qualifier,
+ * country name, locality name, state or province name, organization name, organization
+ * unit name, title, pkcs9 email. Not all the attributes are supported. Please check
+ * the X500NameAttrMap for defined attributes.
+ *
+ * @author Christine Ho
+ */
+
+public final class Attribute implements Serializable, DerEncoder {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -931486084625476764L;
+ //private variables
+ ObjectIdentifier oid;
+ Vector<String> valueSet = new Vector<String>();
+ transient protected X500NameAttrMap attrMap;
+
+ //========== CONSTRUCTOR ==================================
+
+ /**
+ * Construct an attribute from attribute type and attribute value
+ *
+ * @param oid the object identifier of the attribute type
+ * @param value the value string
+ */
+ public Attribute(ObjectIdentifier oid, String value)
+ throws IOException {
+
+ //pre-condition verification
+ if ((oid == null) || (value == null))
+ throw new IOException("Invalid Input - null passed");
+
+ attrMap = X500NameAttrMap.getDefault();
+ this.oid = oid;
+ valueSet.addElement(value);
+ }
+
+ /**
+ * Construct an attribute from attribute type and attribute values
+ *
+ * @param oid the object identifier of the attribute type
+ * @param values String value vector
+ */
+ public Attribute(ObjectIdentifier oid, Vector<String> values)
+ throws IOException {
+
+ //pre-condition verification
+ if ((oid == null) || (values == null))
+ throw new IOException("Invalid Input - null passed");
+
+ attrMap = X500NameAttrMap.getDefault();
+ this.oid = oid;
+
+ //copy the value into the valueSet list
+ Enumeration<String> vals = values.elements();
+ while (vals.hasMoreElements()) {
+ valueSet.addElement(vals.nextElement());
+ }
+ }
+
+ /**
+ * Construct an attribute from attribute type and attribute values
+ *
+ * @param oid attribute type string CN,OU,O,C,L,TITLE,ST,STREET,UID,MAIL,E,DC
+ * @param values String value vector
+ */
+ public Attribute(String attr, Vector<String> values)
+ throws IOException {
+
+ //pre-condition verification
+ if ((attr == null) || (values == null))
+ throw new IOException("Invalid Input - null passed");
+
+ ObjectIdentifier identifier = null;
+ try {
+ identifier = new ObjectIdentifier(attr);
+ } catch (Exception e) {
+ }
+
+ ObjectIdentifier id = identifier;
+ if (identifier == null) {
+ attrMap = X500NameAttrMap.getDefault();
+ id = attrMap.getOid(attr);
+ if (id == null)
+ throw new IOException("Attr is not supported - does not contain in attr map");
+ }
+ this.oid = id;
+
+ //copy the value into the valueSet list
+ Enumeration<String> vals = values.elements();
+ while (vals.hasMoreElements()) {
+ valueSet.addElement(vals.nextElement());
+ }
+ }
+
+ /**
+ * Construct an attribute from a der encoded object. This der
+ * der encoded value should represent the attribute object.
+ *
+ * @param value the attribute object in der encode form.
+ */
+ public Attribute(DerValue val)
+ throws IOException {
+
+ //pre-condition verification
+ if (val == null)
+ throw new IOException("Invalid Input - null passed");
+
+ attrMap = X500NameAttrMap.getDefault();
+
+ decodeThis(val);
+
+ }
+
+ //========== PUBLIC METHODS ==================================
+
+ /**
+ * Returns the OID in the Attribute.
+ *
+ * @return the ObjectIdentifier in this Attribute.
+ */
+ public ObjectIdentifier getOid() {
+ return oid;
+ }
+
+ /**
+ * Returns enumeration of values in this attribute.
+ *
+ * @return Enumeration of values of this Attribute.
+ */
+ public Enumeration<String> getValues() {
+ if (valueSet == null)
+ return null;
+ return valueSet.elements();
+ }
+
+ /**
+ * Encodes the Attribute to a Der output stream.
+ * Attribute are encoded as a SEQUENCE of two elements.
+ *
+ * @param out The Der output stream.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ encodeThis(out);
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ encodeThis(out);
+ }
+
+ /**
+ * Prints a string version of this extension.
+ */
+ public String toString() {
+ String theoid = "Attribute: " + oid + "\n";
+ String values = "Values: ";
+ Enumeration<String> n = valueSet.elements();
+ if (n.hasMoreElements()) {
+ values += n.nextElement();
+ while (n.hasMoreElements())
+ values += "," + n.nextElement();
+ }
+ return theoid + values + "\n";
+ }
+
+ //========== PRIVATE METHODS ==================================
+
+ //encode the attribute object
+ private void encodeThis(OutputStream out)
+ throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream tmp2 = new DerOutputStream();
+
+ tmp.putOID(oid);
+ encodeValueSet(tmp);
+ tmp2.write(DerValue.tag_Sequence, tmp);
+ out.write(tmp2.toByteArray());
+ }
+
+ //encode the attribute object
+ private void encodeValueSet(OutputStream out)
+ throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream tmp2 = new DerOutputStream();
+
+ //get the attribute converter
+ AVAValueConverter converter = attrMap.getValueConverter(oid);
+ if (converter == null) {
+ converter = new GenericValueConverter();
+ //throw new IOException("Converter not found: unsupported attribute type");
+ }
+
+ //loop through all the values and encode
+ Enumeration<String> vals = valueSet.elements();
+ while (vals.hasMoreElements()) {
+ String val = vals.nextElement();
+ DerValue derobj = converter.getValue(val);
+ derobj.encode(tmp);
+ }
+
+ tmp2.write(DerValue.tag_SetOf, tmp);
+ out.write(tmp2.toByteArray());
+ }
+
+ //decode the attribute object
+ private void decodeThis(DerValue val)
+ throws IOException {
+
+ //pre-condition verification
+ if (val == null) {
+ throw new IOException("Invalid Input - null passed.");
+ }
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for Attribute.");
+ }
+
+ if (val.data.available() == 0) {
+ throw new IOException("No data available in "
+ + "passed DER encoded value.");
+ }
+ this.oid = val.data.getDerValue().getOID();
+
+ if (val.data.available() == 0) {
+ throw new IOException("Invalid encoding for Attribute - value missing");
+ }
+ decodeValueSet(val.data.getDerValue());
+
+ if (this.oid == null)
+ throw new IOException("Invalid encoding for Attribute - OID missing");
+
+ }
+
+ //decode the attribute value set
+ private void decodeValueSet(DerValue val)
+ throws IOException {
+ //pre-condition verification
+ if (val == null) {
+ throw new IOException("Invalid Input - null passed.");
+ }
+
+ AVAValueConverter converter = attrMap.getValueConverter(this.oid);
+ if (converter == null) {
+ converter = new GenericValueConverter();
+ //throw new IOException("Attribute is not supported - not in attr map");
+ }
+
+ if (val.tag != DerValue.tag_SetOf) {
+ throw new IOException("Invalid encoding for Attribute Value Set.");
+ }
+
+ if (val.data.available() == 0) {
+ throw new IOException("No data available in "
+ + "passed DER encoded attribute value set.");
+ }
+
+ //get the value set
+ while (val.data.available() != 0) {
+ DerValue value = val.data.getDerValue();
+ valueSet.addElement(converter.getAsString(value));
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/AuthorityKeyIdentifierExtension.java b/base/util/src/netscape/security/x509/AuthorityKeyIdentifierExtension.java
new file mode 100644
index 000000000..91b6c2598
--- /dev/null
+++ b/base/util/src/netscape/security/x509/AuthorityKeyIdentifierExtension.java
@@ -0,0 +1,340 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class represents the Authority Key Identifier Extension.
+ *
+ * <p>
+ * The authority key identifier extension provides a means of identifying the particular public key used to sign a
+ * certificate. This extension would be used where an issuer has multiple signing keys (either due to multiple
+ * concurrent key pairs or due to changeover).
+ * <p>
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * AuthorityKeyIdentifier ::= SEQUENCE {
+ * keyIdentifier [0] KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL
+ * }
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class AuthorityKeyIdentifierExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -157913621972354170L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT =
+ "x509.info.extensions.AuthorityKeyIdentifier";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "AuthorityKeyIdentifier";
+ public static final String KEY_ID = "key_id";
+ public static final String AUTH_NAME = "auth_name";
+ public static final String SERIAL_NUMBER = "serial_number";
+
+ // Private data members
+ private static final byte TAG_ID = 0;
+ private static final byte TAG_NAMES = 1;
+ private static final byte TAG_SERIAL_NUM = 2;
+
+ private KeyIdentifier id = null;
+ private GeneralNames names = null;
+ private SerialNumber serialNum = null;
+
+ // Encode only the extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+ if (id != null) {
+ DerOutputStream tmp1 = new DerOutputStream();
+ id.encode(tmp1);
+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_ID), tmp1);
+ }
+ try {
+ if (names != null) {
+ DerOutputStream tmp1 = new DerOutputStream();
+ names.encode(tmp1);
+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_NAMES), tmp1);
+ }
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ if (serialNum != null) {
+ DerOutputStream tmp1 = new DerOutputStream();
+ serialNum.encode(tmp1);
+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_SERIAL_NUM), tmp1);
+ }
+ seq.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Exposed critical parameter. 99/11/03
+ */
+ public AuthorityKeyIdentifierExtension(boolean critical,
+ KeyIdentifier kid, GeneralNames name,
+ SerialNumber sn)
+ throws IOException {
+ this.id = kid;
+ this.names = name;
+ this.serialNum = sn;
+
+ this.extensionId = PKIXExtensions.AuthorityKey_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * The default constructor for this extension. Null parameters make
+ * the element optional (not present).
+ *
+ * @param id the KeyIdentifier associated with this extension.
+ * @param names the GeneralNames associated with this extension
+ * @param serialNum the CertificateSerialNumber associated with
+ * this extension.
+ * @exception IOException on error.
+ */
+ public AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames name,
+ SerialNumber sn)
+ throws IOException {
+ this.id = kid;
+ this.names = name;
+ this.serialNum = sn;
+
+ this.extensionId = PKIXExtensions.AuthorityKey_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public AuthorityKeyIdentifierExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.AuthorityKey_Id;
+ this.critical = critical.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new IOException("Illegal argument type");
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for " +
+ "AuthorityKeyIdentifierExtension.");
+ }
+
+ // NB. this is always encoded with the IMPLICIT tag
+ // The checks only make sense if we assume implicit tagging,
+ // with explicit tagging the form is always constructed.
+ while (val.data.available() != 0) {
+ DerValue opt = val.data.getDerValue();
+
+ if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) {
+ if (id != null)
+ throw new IOException("Duplicate KeyIdentifier in " +
+ "AuthorityKeyIdentifier.");
+ opt.resetTag(DerValue.tag_OctetString);
+ id = new KeyIdentifier(opt);
+
+ } else if (opt.isContextSpecific(TAG_NAMES) &&
+ opt.isConstructed()) {
+ if (names != null)
+ throw new IOException("Duplicate GeneralNames in " +
+ "AuthorityKeyIdentifier.");
+ try {
+ opt.resetTag(DerValue.tag_Sequence);
+ names = new GeneralNames(opt);
+ } catch (GeneralNamesException e) {
+ throw new IOException(e.toString());
+ }
+
+ } else if (opt.isContextSpecific(TAG_SERIAL_NUM) &&
+ !opt.isConstructed()) {
+ if (serialNum != null)
+ throw new IOException("Duplicate SerialNumber in " +
+ "AuthorityKeyIdentifier.");
+ opt.resetTag(DerValue.tag_Integer);
+ serialNum = new SerialNumber(opt);
+ } else
+ throw new IOException("Invalid encoding of " +
+ "AuthorityKeyIdentifierExtension.");
+ }
+ }
+
+ /**
+ * Return the object as a string.
+ */
+ public String toString() {
+ String s = super.toString() + "AuthorityKeyIdentifier [\n";
+ if (id != null) {
+ s += id.toString();
+ }
+ if (names != null) {
+ s += names.toString() + "\n";
+ }
+ if (serialNum != null) {
+ s += serialNum.toString() + "\n";
+ }
+ return (s + "]\n");
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on error.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (this.extensionValue == null) {
+ extensionId = PKIXExtensions.AuthorityKey_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ if (!(obj instanceof KeyIdentifier)) {
+ throw new IOException("Attribute value should be of " +
+ "type KeyIdentifier.");
+ }
+ id = (KeyIdentifier) obj;
+ } else if (name.equalsIgnoreCase(AUTH_NAME)) {
+ if (!(obj instanceof GeneralNames)) {
+ throw new IOException("Attribute value should be of " +
+ "type GeneralNames.");
+ }
+ names = (GeneralNames) obj;
+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
+ if (!(obj instanceof SerialNumber)) {
+ throw new IOException("Attribute value should be of " +
+ "type SerialNumber.");
+ }
+ serialNum = (SerialNumber) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:AuthorityKeyIdentifier.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ return (id);
+ } else if (name.equalsIgnoreCase(AUTH_NAME)) {
+ return (names);
+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
+ return (serialNum);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:AuthorityKeyIdentifier.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ id = null;
+ } else if (name.equalsIgnoreCase(AUTH_NAME)) {
+ names = null;
+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
+ serialNum = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:AuthorityKeyIdentifier.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(KEY_ID);
+ elements.addElement(AUTH_NAME);
+ elements.addElement(SERIAL_NUMBER);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/BasicConstraintsExtension.java b/base/util/src/netscape/security/x509/BasicConstraintsExtension.java
new file mode 100644
index 000000000..2688e961d
--- /dev/null
+++ b/base/util/src/netscape/security/x509/BasicConstraintsExtension.java
@@ -0,0 +1,295 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class represents the Basic Constraints Extension.
+ *
+ * <p>
+ * The basic constraints extension identifies whether the subject of the certificate is a CA and how deep a
+ * certification path may exist through that CA.
+ *
+ * <pre>
+ * The ASN.1 syntax for this extension is:
+ * BasicConstraints ::= SEQUENCE {
+ * cA BOOLEAN DEFAULT FALSE,
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL
+ * }
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ * @see CertAttrSet
+ * @see Extension
+ */
+public class BasicConstraintsExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6213957094939885889L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.BasicConstraints";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "BasicConstraints";
+ public static final String IS_CA = "is_ca";
+ public static final String PATH_LEN = "path_len";
+
+ // Private data members
+ private boolean ca = false;
+ private int pathLen = -1;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (ca) {
+ tmp.putBoolean(ca);
+ }
+ if (pathLen >= 0) {
+ tmp.putInteger(new BigInt(pathLen));
+ }
+ out.write(DerValue.tag_Sequence, tmp);
+ this.extensionValue = out.toByteArray();
+ }
+
+ /**
+ * Default constructor for this object.
+ *
+ * @param ca true, if the subject of the Certificate is a CA.
+ * @param len specifies the depth of the certification path.
+ */
+ public BasicConstraintsExtension(boolean ca, int len) throws IOException {
+ this.ca = ca;
+ this.pathLen = len;
+ this.extensionId = PKIXExtensions.BasicConstraints_Id;
+ if (ca) {
+ critical = true;
+ } else {
+ critical = false;
+ }
+ encodeThis();
+ }
+
+ /**
+ * Default constructor for this object.
+ *
+ * @param ca true, if the subject of the Certificate is a CA.
+ * @param len specifies the depth of the certification path.
+ */
+ public BasicConstraintsExtension(boolean ca, boolean critical, int len) throws IOException {
+ this.ca = ca;
+ this.pathLen = len;
+ this.extensionId = PKIXExtensions.BasicConstraints_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param extension the DER encoded value of the extension.
+ * @exception IOException on error.
+ */
+ public BasicConstraintsExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.BasicConstraints_Id;
+ this.critical = critical.booleanValue();
+
+ if (value instanceof byte[]) {
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of BasicConstraints");
+ }
+
+ // non-CA cert with no limit to certification path length
+ if (val.data == null || val.data.available() < 1) {
+ this.ca = false;
+ this.pathLen = -1;
+ return;
+ }
+ DerValue opt = val.data.getDerValue();
+ if (opt.tag != DerValue.tag_Boolean) {
+ this.ca = false;
+ } else {
+ this.ca = true;
+ if (val.data.available() != 0) {
+ opt = val.data.getDerValue();
+ } else {
+ this.pathLen = -1;
+ return;
+ }
+ }
+ if (opt.tag != DerValue.tag_Integer) {
+ throw new IOException("Invalid encoding of BasicConstraints");
+ }
+ this.pathLen = (opt.getInteger()).toInt();
+ /*
+ * Activate this check once again after PKIX profiling
+ * is a standard and this check no longer imposes an
+ * interoperability barrier.
+ * if (ca) {
+ * if (!this.critical) {
+ * throw new IOException("Criticality cannot be false for CA.");
+ * }
+ * }
+ */
+ } else
+ throw new IOException("Invalid argument type");
+ }
+
+ /**
+ * Return user readable form of extension.
+ */
+ public String toString() {
+ String s = super.toString() + "BasicConstraints:[\n";
+
+ s += ((ca) ? ("CA:true") : ("CA:false")) + "\n";
+ if (pathLen >= 0) {
+ s += "PathLen:" + pathLen + "\n";
+ } else {
+ s += "PathLen: undefined\n";
+ }
+ return (s + "]\n");
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Encode this extension value to the output stream.
+ *
+ * @param out the DerOutputStream to encode the extension to.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ this.extensionId = PKIXExtensions.BasicConstraints_Id;
+ /* #57286 - so that profile can set critiality */
+ /*
+ if (ca) {
+ critical = true;
+ } else {
+ critical = false;
+ }
+ */
+ encodeThis();
+ }
+ super.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(IS_CA)) {
+ if (!(obj instanceof Boolean)) {
+ throw new IOException("Attribute value should be of type Boolean.");
+ }
+ ca = ((Boolean) obj).booleanValue();
+ } else if (name.equalsIgnoreCase(PATH_LEN)) {
+ if (!(obj instanceof Integer)) {
+ throw new IOException("Attribute value should be of type Integer.");
+ }
+ pathLen = ((Integer) obj).intValue();
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:BasicConstraints.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(IS_CA)) {
+ return (new Boolean(ca));
+ } else if (name.equalsIgnoreCase(PATH_LEN)) {
+ return (Integer.valueOf(pathLen));
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:BasicConstraints.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(IS_CA)) {
+ ca = false;
+ } else if (name.equalsIgnoreCase(PATH_LEN)) {
+ pathLen = -1;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:BasicConstraints.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(IS_CA);
+ elements.addElement(PATH_LEN);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CPSuri.java b/base/util/src/netscape/security/x509/CPSuri.java
new file mode 100644
index 000000000..d0a2e0762
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CPSuri.java
@@ -0,0 +1,66 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CPSuri Qualifier.
+ *
+ * CPSuri ::= IA5String;
+ *
+ * @author Thomas Kwan
+ */
+public class CPSuri extends Qualifier {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2814961293159006960L;
+ private String mURI = null;
+
+ /**
+ * Create a PolicyQualifierInfo
+ *
+ * @param id the ObjectIdentifier for the policy id.
+ */
+ public CPSuri(String uri) {
+ mURI = uri;
+ }
+
+ public CPSuri(DerValue val) throws IOException {
+ mURI = val.getIA5String();
+ }
+
+ /**
+ * Write the PolicyQualifier to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putIA5String(mURI);
+ }
+
+ public String getURI() {
+ return mURI;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CRLDistributionPoint.java b/base/util/src/netscape/security/x509/CRLDistributionPoint.java
new file mode 100644
index 000000000..c7ad84389
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CRLDistributionPoint.java
@@ -0,0 +1,467 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * <pre>
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL }
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6) }
+ * </pre>
+ */
+public class CRLDistributionPoint implements ASN1Value {
+
+ // at most one of the two following may be specified:
+ private GeneralNames fullName;
+ private RDN relativeName;
+
+ // cache encoding of fullName
+ private ANY fullNameEncoding;
+
+ private BitArray reasons; // optional, may be null
+ private GeneralNames CRLIssuer; // optional, may be null
+ private ANY CRLIssuerEncoding;
+
+ // default constructor does nothing.
+
+ /**
+ * Returns the <code>fullName</code> of the <code>DistributionPointName</code>, which may be <code>null</code>.
+ */
+ public GeneralNames getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Returns the <code>relativeName</code> of the <code>DistributionPointName</code>, which may be <code>null</code>.
+ */
+ public RDN getRelativeName() {
+ return relativeName;
+ }
+
+ /**
+ * Sets the <code>fullName</code> of the <code>DistributionPointName</code>. It may be set to <code>null</code>.
+ * If it is set to a non-null value, <code>relativeName</code> will be
+ * set to <code>null</code>, because at most one of these two attributes
+ * can be specified at a time.
+ *
+ * @exception GeneralNamesException If an error occurs encoding the
+ * name.
+ */
+ public void setFullName(GeneralNames fullName)
+ throws GeneralNamesException, IOException {
+ this.fullName = fullName;
+ if (fullName != null) {
+ // encode the name to catch any problems with it
+ DerOutputStream derOut = new DerOutputStream();
+ fullName.encode(derOut);
+ try {
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(0), bos);
+ fullNameEncoding = new ANY(bos.toByteArray());
+ } catch (InvalidBERException e) {
+ // assume this won't happen, since it would imply a bug
+ // in DerOutputStream
+ throw new GeneralNamesException(e.toString());
+ }
+
+ this.relativeName = null;
+ }
+ }
+
+ /**
+ * Sets the <code>relativeName</code> of the <code>DistributionPointName</code>. It may be set to <code>null</code>.
+ * If it is set to a non-null value, <code>fullName</code> will be
+ * set to <code>null</code>, because at most one of these two attributes
+ * can be specified at a time.
+ */
+ public void setRelativeName(RDN relativeName) {
+ this.relativeName = relativeName;
+ if (relativeName != null) {
+ this.fullName = null;
+ }
+ }
+
+ /**
+ * Returns the reason flags for this distribution point. May be <code>null</code>.
+ */
+ public BitArray getReasons() {
+ return reasons;
+ }
+
+ /**
+ * Sets the reason flags for this distribution point. May be set to <code>null</code>.
+ */
+ public void setReasons(BitArray reasons) {
+ this.reasons = reasons;
+ }
+
+ /**
+ * Returns the CRLIssuer for the CRL at this distribution point.
+ * May be <code>null</code>.
+ */
+ public GeneralNames getCRLIssuer() {
+ return CRLIssuer;
+ }
+
+ /**
+ * Sets the CRLIssuer for the CRL at this distribution point.
+ * May be set to <code>null</code>.
+ *
+ * @exception GeneralNamesException If an error occurs encoding the name.
+ */
+ public void setCRLIssuer(GeneralNames CRLIssuer)
+ throws GeneralNamesException, IOException {
+ this.CRLIssuer = CRLIssuer;
+
+ if (CRLIssuer != null) {
+ // encode the name to catch any problems with it
+ DerOutputStream derOut = new DerOutputStream();
+ CRLIssuer.encode(derOut);
+ try {
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(2), bos);
+ CRLIssuerEncoding = new ANY(bos.toByteArray());
+ } catch (InvalidBERException e) {
+ throw new GeneralNamesException(e.toString());
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////////////////
+ // DER encoding
+ /////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+ SEQUENCE seq = new SEQUENCE();
+ DerOutputStream derOut;
+
+ try {
+
+ // Encodes the DistributionPointName. Because DistributionPointName
+ // is a CHOICE, the [0] tag is forced to be EXPLICIT.
+ if (fullName != null) {
+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), fullNameEncoding);
+ seq.addElement(distPoint);
+ } else if (relativeName != null) {
+ derOut = new DerOutputStream();
+ relativeName.encode(derOut);
+ ANY rn = new ANY(derOut.toByteArray());
+ EXPLICIT raw = new EXPLICIT(Tag.get(1), rn);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encode(bos);
+ ANY distPointName = new ANY(bos.toByteArray());
+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), distPointName);
+ seq.addElement(distPoint);
+ }
+
+ // Encodes the ReasonFlags.
+ if (reasons != null) {
+ derOut = new DerOutputStream();
+ derOut.putUnalignedBitString(reasons);
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(1), bos);
+ ANY reasonEncoding = new ANY(bos.toByteArray());
+ seq.addElement(Tag.get(1), reasonEncoding);
+ }
+
+ // Encodes the CRLIssuer
+ if (CRLIssuer != null) {
+ seq.addElement(Tag.get(2), CRLIssuerEncoding);
+ }
+
+ seq.encode(implicitTag, ostream);
+
+ } catch (InvalidBERException e) {
+ // this shouldn't happen unless there is a bug in one of
+ // the Sun encoding classes
+ throw new IOException(e.toString());
+ }
+ }
+
+ // Template singleton
+ private static Template templateInstance = new Template();
+
+ /**
+ * Returns an instance of a template for decoding a CRLDistributionPoint.
+ */
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ public static void main(String args[]) {
+ try {
+ if (args.length != 1) {
+ System.out.println("Usage: CRLDistributionPoint <outfile>");
+ System.exit(-1);
+ }
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ SEQUENCE cdps = new SEQUENCE();
+
+ // URI only
+ CRLDistributionPoint cdp = new CRLDistributionPoint();
+ URIName uri = new URIName("http://www.mycrl.com/go/here");
+ GeneralNames generalNames = new GeneralNames();
+ generalNames.addElement(uri);
+ cdp.setFullName(generalNames);
+ cdps.addElement(cdp);
+
+ // DN only
+ cdp = new CRLDistributionPoint();
+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" +
+ ",OU=Certificate Server,O=Fedora,C=US");
+ generalNames = new GeneralNames();
+ generalNames.addElement(dn);
+ cdp.setFullName(generalNames);
+ cdps.addElement(cdp);
+
+ // DN + reason
+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 });
+ cdp = new CRLDistributionPoint();
+ cdp.setFullName(generalNames);
+ cdp.setReasons(ba);
+ cdps.addElement(cdp);
+
+ // relative DN + reason + crlIssuer
+ cdp = new CRLDistributionPoint();
+ RDN rdn = new RDN("OU=foobar dept");
+ cdp.setRelativeName(rdn);
+ cdp.setReasons(ba);
+ cdp.setCRLIssuer(generalNames);
+ cdps.addElement(cdp);
+
+ cdps.encode(bos);
+
+ byte[] encoded = bos.toByteArray();
+ (new FileOutputStream(args[0])).write(encoded);
+
+ SEQUENCE.OF_Template seqt = new SEQUENCE.OF_Template(getTemplate());
+
+ cdps = (SEQUENCE) ASN1Util.decode(seqt, encoded);
+
+ int size = cdps.size();
+ System.out.println("Total number of CDPs: " + size);
+ for (int i = 0; i < size; i++) {
+ System.out.println("\nCDP " + i);
+ cdp = (CRLDistributionPoint) cdps.elementAt(i);
+ GeneralNames gn = cdp.getFullName();
+ if (gn == null) {
+ System.out.println("No full name");
+ } else {
+ System.out.println(gn);
+ }
+ rdn = cdp.getRelativeName();
+ if (rdn == null) {
+ System.out.println("No relative name");
+ } else {
+ System.out.println(rdn);
+ }
+ if (cdp.getReasons() == null) {
+ System.out.println("No reasons");
+ } else {
+ System.out.println(cdp.getReasons());
+ }
+ gn = cdp.getCRLIssuer();
+ if (gn == null) {
+ System.out.println("No cRLIssuer");
+ } else {
+ System.out.println(gn);
+ }
+ }
+ System.out.println("Done");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Template for decoding CRLDistributionPoint.
+ */
+ public static class Template implements ASN1Template {
+
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ public ASN1Value decode(InputStream istream)
+ throws IOException, InvalidBERException {
+ return decode(TAG, istream);
+ }
+
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws IOException, InvalidBERException {
+ CRLDistributionPoint cdp = new CRLDistributionPoint();
+
+ //
+ // construct the top-level sequence
+ //
+
+ SEQUENCE.Template seqt = SEQUENCE.getTemplate();
+
+ // distributionPoint
+ seqt.addOptionalElement(
+ new EXPLICIT.Template(Tag.get(0), ANY.getTemplate()));
+
+ // reasons
+ seqt.addOptionalElement(Tag.get(1), BIT_STRING.getTemplate());
+
+ // cRLIssuer
+ // This will have a tag of 2, but we can't say that here
+ // because ANYs can't have implicit tags. We don't need to say
+ // it, because we do check the tags on the other two elements
+ // in the sequence, so we'll know if we get this one.
+ seqt.addOptionalElement(ANY.getTemplate());
+
+ //
+ // decode the top-level sequence
+ //
+ SEQUENCE top = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ // decode the distribution point name
+ if (top.elementAt(0) != null) {
+ EXPLICIT exp = (EXPLICIT) top.elementAt(0);
+ ANY distPoint = (ANY) exp.getContent();
+ if (distPoint.getTag().equals(Tag.get(0))) {
+ // fullName
+ try {
+ DerValue dv = new DerValue(distPoint.getEncoded());
+ //toFile("encodedFullName", distPoint.getEncoded());
+ dv.resetTag(DerValue.tag_Sequence);
+ cdp.setFullName(new GeneralNames(dv));
+ } catch (GeneralNamesException e) {
+ throw new InvalidBERException("fullName: " + e.toString());
+ } catch (IOException e) {
+ throw new InvalidBERException("fullName: " + e.toString());
+ }
+ } else if (distPoint.getTag().equals(Tag.get(1))) {
+ // relative name
+ try {
+ DerValue dv = new DerValue(distPoint.getEncoded());
+ /* dv is as follows:
+ 0 12: [1] {
+ 2 10: SET {
+ 4 8: SEQUENCE {
+ 6 3: OBJECT IDENTIFIER commonName (2 5 4 3)
+ 11 1: PrintableString 'x'
+ : }
+ : }
+ : }
+ */
+ dv = dv.data.getDerValue(); // skipping the tag
+ /* after the skipping, we have:
+ 0 10: SET {
+ 2 8: SEQUENCE {
+ 4 3: OBJECT IDENTIFIER commonName (2 5 4 3)
+ 9 1: PrintableString 'x'
+ : }
+ : }
+ */
+ dv.resetTag(DerValue.tag_Set);
+ cdp.setRelativeName(new RDN(dv));
+ } catch (IOException e) {
+ throw new InvalidBERException("relativeName " +
+ e.toString());
+ }
+ } else {
+ throw new InvalidBERException(
+ "Unknown tag " + distPoint.getTag() +
+ " in distributionPoint");
+ }
+ }
+
+ // decode the reasons
+ if (top.elementAt(1) != null) {
+ BIT_STRING bs = (BIT_STRING) top.elementAt(1);
+ byte[] bits = bs.getBits();
+ cdp.setReasons(
+ new BitArray((bits.length * 8) - bs.getPadCount(), bits));
+ }
+
+ // decode the cRLIssuer
+ if (top.elementAt(2) != null) {
+ ANY issuer = (ANY) top.elementAt(2);
+ if (!issuer.getTag().equals(Tag.get(2))) {
+ throw new InvalidBERException("Invalid tag " + issuer.getTag());
+ }
+ try {
+ DerValue dv = new DerValue(issuer.getEncoded());
+ dv.resetTag(DerValue.tag_Sequence);
+ cdp.setCRLIssuer(new GeneralNames(dv));
+ } catch (GeneralNamesException e) {
+ throw new InvalidBERException("cRLIssuer " + e.toString());
+ } catch (IOException e) {
+ throw new InvalidBERException("cRLIssuer " + e.toString());
+ }
+ }
+
+ return cdp;
+
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/CRLDistributionPointsExtension.java b/base/util/src/netscape/security/x509/CRLDistributionPointsExtension.java
new file mode 100644
index 000000000..c939a7431
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CRLDistributionPointsExtension.java
@@ -0,0 +1,391 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+
+/**
+ * An extension that tells applications where to find the CRL for
+ * this certificate.
+ *
+ * <pre>
+ * cRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL }
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6) }
+ * </pre>
+ */
+public class CRLDistributionPointsExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8551761833349709229L;
+ // vector of CRLDistributionPoint
+ private SEQUENCE distributionPoints = new SEQUENCE();
+
+ // Cached DER-encoding to improve performance.
+ private byte[] cachedEncoding = null;
+
+ /**
+ * This constructor is called by the CertificateExtensions class to decode
+ * an extension whose OID indicates it is a CRLDistributionsPoints
+ * extension.
+ */
+ public CRLDistributionPointsExtension(Boolean critical, Object value)
+ //throws IOException
+ {
+ try {
+
+ this.extensionId = PKIXExtensions.CRLDistributionPoints_Id;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+
+ // decode the value
+ try {
+ SEQUENCE.OF_Template seqOfCRLDP =
+ new SEQUENCE.OF_Template(CRLDistributionPoint.getTemplate());
+
+ distributionPoints =
+ (SEQUENCE) ASN1Util.decode(seqOfCRLDP, extensionValue);
+ } catch (InvalidBERException e) {
+ throw new IOException("Invalid BER-encoding: " + e.toString());
+ }
+ } catch (IOException e) {
+ System.out.println("Big error");
+ System.out.println(e);
+ e.printStackTrace();
+ //throw e;
+ }
+ }
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.31";
+
+ /**
+ * Creates a new CRLDistributionPoints extension, with the given
+ * distribution point as the first element.
+ */
+ public CRLDistributionPointsExtension(CRLDistributionPoint dp) {
+ this.extensionId = PKIXExtensions.CRLDistributionPoints_Id;
+ this.critical = false;
+ distributionPoints.addElement(dp);
+ }
+
+ /**
+ * Adds an additional distribution point to the end of the sequence.
+ */
+ public void addPoint(CRLDistributionPoint dp) {
+ distributionPoints.addElement(dp);
+ cachedEncoding = null;
+ }
+
+ /**
+ * Returns the number of distribution points in the sequence.
+ */
+ public int getNumPoints() {
+ return distributionPoints.size();
+ }
+
+ /**
+ * Returns the DistributionPoint at the given index in the sequence.
+ */
+ public CRLDistributionPoint getPointAt(int index) {
+ return (CRLDistributionPoint) distributionPoints.elementAt(index);
+ }
+
+ /**
+ * Sets the criticality of this extension. PKIX dictates that this
+ * extension SHOULD NOT be critical, so applications can make it critical
+ * if they have a very good reason. By default, the extension is not
+ * critical.
+ */
+ public void setCritical(boolean critical) {
+ this.critical = critical;
+ }
+
+ /**
+ * Encodes this extension to the given DerOutputStream.
+ * This method re-encodes each time it is called, so it is not very
+ * efficient.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ extensionValue = ASN1Util.encode(distributionPoints);
+ super.encode(out);
+ }
+
+ /**
+ * Should be called if any change is made to this data structure
+ * so that the cached DER encoding can be discarded.
+ */
+ public void flushCachedEncoding() {
+ cachedEncoding = null;
+ }
+
+ /////////////////////////////////////////////////////////////
+ // CertAttrSet interface
+ // This interface is not really appropriate for this extension
+ // because it is so complicated. Therefore, we only provide a
+ // minimal implementation.
+ /////////////////////////////////////////////////////////////
+ public static final String NAME = "CRLDistributionPoints";
+
+ static {
+ try {
+ OIDMap.addAttribute(CRLDistributionPointsExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ /**
+ * DER-encodes this extension to the given OutputStream.
+ */
+ public void encode(OutputStream ostream)
+ throws CertificateException, IOException {
+ if (cachedEncoding == null) {
+ // only re-encode if necessary
+ DerOutputStream tmp = new DerOutputStream();
+ encode(tmp);
+ cachedEncoding = tmp.toByteArray();
+ }
+ ostream.write(cachedEncoding);
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ throw new IOException("Not supported");
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CRLDistributionPointsExtension");
+ }
+
+ public Object get(String name)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CRLDistributionPointsExtension");
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CRLDistributionPointsExtension");
+ }
+
+ /*
+ * TODO use an empty collection to generate these
+ */
+ public Enumeration<String> getAttributeNames() {
+ return (new Vector<String>()).elements();
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Test driver.
+ */
+ public static void main(String args[]) {
+
+ try {
+
+ if (args.length != 1) {
+ System.out.println("Usage: CRLDistributionPointsExtentions " +
+ "<outfile>");
+ System.exit(-1);
+ }
+
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(args[0]));
+
+ // URI only
+ CRLDistributionPoint cdp = new CRLDistributionPoint();
+ URIName uri = new URIName("http://www.mycrl.com/go/here");
+ GeneralNames generalNames = new GeneralNames();
+ generalNames.addElement(uri);
+ cdp.setFullName(generalNames);
+ CRLDistributionPointsExtension crldpExt =
+ new CRLDistributionPointsExtension(cdp);
+
+ // DN only
+ cdp = new CRLDistributionPoint();
+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" +
+ ",OU=Certificate Server,O=Fedora,C=US");
+ generalNames = new GeneralNames();
+ generalNames.addElement(dn);
+ cdp.setFullName(generalNames);
+ crldpExt.addPoint(cdp);
+
+ // DN + reason
+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 });
+ cdp = new CRLDistributionPoint();
+ cdp.setFullName(generalNames);
+ cdp.setReasons(ba);
+ crldpExt.addPoint(cdp);
+
+ // relative DN + reason + crlIssuer
+ cdp = new CRLDistributionPoint();
+ RDN rdn = new RDN("OU=foobar dept");
+ cdp.setRelativeName(rdn);
+ cdp.setReasons(ba);
+ cdp.setCRLIssuer(generalNames);
+ crldpExt.addPoint(cdp);
+
+ crldpExt.setCritical(true);
+ crldpExt.encode(bos);
+
+ bos.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Represents a reason that a cert may be revoked. These reasons are
+ * expressed in a ReasonFlags bit string.
+ */
+ public static class Reason {
+
+ private String name;
+ private byte bitMask;
+
+ private Reason() {
+ }
+
+ private Reason(String name, byte bitMask) {
+ this.name = name;
+ this.bitMask = bitMask;
+ map.put(name, this);
+ list.addElement(this);
+ }
+
+ private static Hashtable<String, Reason> map = new Hashtable<String, Reason>();
+ private static Vector<Reason> list = new Vector<Reason>();
+
+ public static Reason fromString(String name) {
+ return map.get(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public byte getBitMask() {
+ return bitMask;
+ }
+
+ /**
+ * Given a bit array representing reason flags, extracts the reasons
+ * and returns them as an array.
+ *
+ * @param bitFlags A bit vector containing reason flags.
+ * @return An array of reasons contained in the bit vector.
+ * May be zero-length but will not be null.
+ */
+ public static Reason[] bitArrayToReasonArray(byte bitFlags) {
+ return bitArrayToReasonArray(new byte[] { bitFlags });
+ }
+
+ /**
+ * Given a bit array representing reason flags, extracts the reasons
+ * and returns them as an array. Currently, only the first byte
+ * of the bitflags are examined.
+ *
+ * @param bitFlags A bit vector containing reason flags. The format
+ * is big-endian (MSB first). Only the first byte is examined.
+ * @return An array of reasons contained in the bit vector.
+ * May be zero-length but will not be null.
+ */
+ public static Reason[] bitArrayToReasonArray(byte[] bitFlags) {
+ byte first = bitFlags[0];
+ int size = list.size();
+ Vector<Reason> result = new Vector<Reason>();
+ for (int i = 0; i < size; i++) {
+ Reason r = list.elementAt(i);
+ byte b = r.getBitMask();
+ if ((first & b) != 0) {
+ result.addElement(r);
+ }
+ }
+ size = result.size();
+ Reason[] retval = new Reason[size];
+ for (int i = 0; i < size; i++) {
+ retval[i] = result.elementAt(i);
+ }
+ return retval;
+ }
+
+ public static final Reason UNUSED =
+ new Reason("unused", (byte) 0x80);
+ public static final Reason KEY_COMPROMISE =
+ new Reason("keyCompromise", (byte) 0x40);
+ public static final Reason CA_COMPROMISE =
+ new Reason("cACompromise", (byte) 0x20);
+ public static final Reason AFFILIATION_CHANGED =
+ new Reason("affiliationChanged", (byte) 0x10);
+ public static final Reason SUPERSEDED =
+ new Reason("superseded", (byte) 0x08);
+ public static final Reason CESSATION_OF_OPERATION =
+ new Reason("cessationOfOperation", (byte) 0x04);
+ public static final Reason CERTIFICATE_HOLD =
+ new Reason("certificateHold", (byte) 0x02);
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/CRLExtensions.java b/base/util/src/netscape/security/x509/CRLExtensions.java
new file mode 100755
index 000000000..bdadcc12e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CRLExtensions.java
@@ -0,0 +1,229 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the CRL Extensions.
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class CRLExtensions extends Vector<Extension> {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 365767738692986418L;
+ private Hashtable<String, Extension> map;
+
+ // Parse the encoded extension
+ private void parseExtension(Extension ext) throws X509ExtensionException {
+ try {
+ Class<?> extClass = OIDMap.getClass(ext.getExtensionId());
+ if (extClass == null) { // Unsupported extension
+ if (ext.isCritical()) {
+ throw new IOException("Unsupported CRITICAL extension: "
+ + ext.getExtensionId());
+ } else {
+ map.put(ext.getExtensionId().toString(), ext);
+ addElement(ext);
+ return;
+ }
+ }
+ Class<?>[] params = { Boolean.class, Object.class };
+ Constructor<?> cons = extClass.getConstructor(params);
+ byte[] extData = ext.getExtensionValue();
+ int extLen = extData.length;
+ Object value = Array.newInstance(byte.class, extLen);
+
+ for (int i = 0; i < extLen; i++) {
+ Array.setByte(value, i, extData[i]);
+ }
+ Object[] passed = new Object[] { new Boolean(ext.isCritical()),
+ value };
+ CertAttrSet crlExt = (CertAttrSet) cons.newInstance(passed);
+ map.put(crlExt.getName(), (Extension) crlExt);
+ addElement((Extension) crlExt);
+
+ } catch (InvocationTargetException invk) {
+ throw new X509ExtensionException(
+ invk.getTargetException().getMessage());
+
+ } catch (Exception e) {
+ throw new X509ExtensionException(e.toString());
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ public CRLExtensions() {
+ map = new Hashtable<String, Extension>();
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the Extension from.
+ * @exception CRLException on decoding errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public CRLExtensions(DerInputStream in)
+ throws CRLException, X509ExtensionException {
+
+ map = new Hashtable<String, Extension>();
+ try {
+ DerValue[] exts = in.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.toString());
+ }
+ }
+
+ /**
+ * Decode the extensions from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception CRLException on decoding or validity errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public void decode(InputStream in)
+ throws CRLException, X509ExtensionException {
+ try {
+ DerValue val = new DerValue(in);
+ DerInputStream str = val.toDerInputStream();
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = str.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.toString());
+ }
+ }
+
+ /**
+ * Encode the extensions in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @param isExplicit the tag indicating whether this is an entry
+ * extension or a CRL extension.
+ * @exception CRLException on encoding errors.
+ */
+ public void encode(OutputStream out, boolean isExplicit)
+ throws CRLException {
+ try {
+ // #381559
+ if (size() == 0)
+ return;
+ DerOutputStream extOut = new DerOutputStream();
+ for (int i = 0; i < size(); i++) {
+ Object thisOne = elementAt(i);
+ if (thisOne instanceof CertAttrSet)
+ ((CertAttrSet) thisOne).encode(extOut);
+ else if (thisOne instanceof Extension)
+ ((Extension) thisOne).encode(extOut);
+ else
+ throw new CRLException("Illegal extension object");
+ }
+
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.tag_Sequence, extOut);
+
+ DerOutputStream tmp = new DerOutputStream();
+ if (isExplicit)
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) 0), seq);
+ else
+ tmp = seq;
+
+ out.write(tmp.toByteArray());
+ } catch (IOException e) {
+ throw new CRLException("Encoding error: " + e.toString());
+ } catch (CertificateException e) {
+ throw new CRLException("Encoding error: " + e.toString());
+ }
+ }
+
+ /**
+ * Get the extension with this alias.
+ *
+ * @param alias the identifier string for the extension to retrieve.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public Extension get(String alias) throws X509ExtensionException {
+ X509AttributeName attr = new X509AttributeName(alias);
+ String name;
+ String id = attr.getPrefix();
+ if (id.equalsIgnoreCase(X509CertImpl.NAME)) { // fully qualified
+ int index = alias.lastIndexOf(".");
+ name = alias.substring(index + 1);
+ } else
+ name = alias;
+ Extension ext = (Extension) map.get(name);
+ if (ext == null)
+ throw new X509ExtensionException("No extension found with name: "
+ + alias);
+ return ext;
+ }
+
+ /**
+ * Set the extension value with this alias.
+ *
+ * @param alias the identifier string for the extension to set.
+ * @param obj the Object to set the extension identified by the
+ * alias.
+ * @exception IOException on errors.
+ */
+ public void set(String alias, Extension obj) throws IOException {
+ map.put(alias, obj);
+ addElement(obj);
+ }
+
+ /**
+ * Return an enumeration of names of the extensions.
+ *
+ * @return an enumeration of the names of the extensions in this CRL.
+ */
+ public Enumeration<Extension> getElements() {
+ return (map.elements());
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CRLNumberExtension.java b/base/util/src/netscape/security/x509/CRLNumberExtension.java
new file mode 100755
index 000000000..7c89b179f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CRLNumberExtension.java
@@ -0,0 +1,226 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CRL Number Extension.
+ *
+ * <p>
+ * This extension, if present, conveys a monotonically increasing sequence number for each CRL issued by a given CA
+ * through a specific CA X.500 Directory entry or CRL distribution point. This extension allows users to easily
+ * determine when a particular CRL supersedes another CRL.
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.2
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class CRLNumberExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2992307666566322402L;
+ /**
+ * Attribute name.
+ */
+ public static final String NAME = "CRLNumber";
+ public static final String NUMBER = "value";
+
+ private BigInt crlNumber = null;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ if (crlNumber == null)
+ throw new IOException("Unintialized CRL number extension");
+ DerOutputStream os = new DerOutputStream();
+ os.putInteger(this.crlNumber);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a CRLNumberExtension with the integer value .
+ * The criticality is set to false.
+ *
+ * @param crlNum the value to be set for the extension.
+ */
+ public CRLNumberExtension(int crlNum) throws IOException {
+ this.crlNumber = new BigInt(crlNum);
+ this.extensionId = PKIXExtensions.CRLNumber_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a CRLNumberExtension with the BigInteger value .
+ * The criticality is set to false.
+ *
+ * @param crlNum the value to be set for the extension.
+ */
+ public CRLNumberExtension(BigInteger crlNum) throws IOException {
+ this.crlNumber = new BigInt(crlNum);
+ this.extensionId = PKIXExtensions.CRLNumber_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a CRLNumberExtension with the BigInteger value .
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param crlNum the value to be set for the extension.
+ */
+ public CRLNumberExtension(Boolean critical, BigInteger crlNum) throws IOException {
+ this.crlNumber = new BigInt(crlNum);
+ this.extensionId = PKIXExtensions.CRLNumber_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public CRLNumberExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.CRLNumber_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ this.crlNumber = val.getInteger();
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ if (!(obj instanceof BigInteger)) {
+ throw new IOException("Attribute must be of type BigInteger.");
+ }
+ crlNumber = new BigInt((BigInteger) obj);
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:CRLNumber.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ if (crlNumber == null)
+ return null;
+ else
+ return crlNumber.toBigInteger();
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:CRLNumber.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ crlNumber = null;
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:CRLNumber.");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the CRLNumberExtension.
+ */
+ public String toString() {
+ String s = super.toString() + "CRL Number: " +
+ ((crlNumber == null) ? "" : crlNumber.toString())
+ + "\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.CRLNumber_Id;
+ this.critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NUMBER);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CRLReasonExtension.java b/base/util/src/netscape/security/x509/CRLReasonExtension.java
new file mode 100644
index 000000000..3c11fc70b
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CRLReasonExtension.java
@@ -0,0 +1,234 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CRLReason Extension of CRL entry.
+ *
+ * <p>
+ * This extension, if present, defines the identifies the reason for the certificate revocation.
+ *
+ * @author galperin
+ * @version $Revision$, $Date$
+ * @see Extension
+ * @see CertAttrSet
+ */
+
+public final class CRLReasonExtension extends Extension implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4544973296866779535L;
+ /**
+ * Canned instances for all revocation reasons
+ */
+ public static final CRLReasonExtension UNSPECIFIED = new CRLReasonExtension(RevocationReason.UNSPECIFIED);
+ public static final CRLReasonExtension KEY_COMPROMISE = new CRLReasonExtension(RevocationReason.KEY_COMPROMISE);
+ public static final CRLReasonExtension CA_COMPROMISE = new CRLReasonExtension(RevocationReason.CA_COMPROMISE);
+ public static final CRLReasonExtension AFFILIATION_CHANGED = new CRLReasonExtension(
+ RevocationReason.AFFILIATION_CHANGED);
+ public static final CRLReasonExtension SUPERSEDED = new CRLReasonExtension(RevocationReason.SUPERSEDED);
+ public static final CRLReasonExtension CESSATION_OF_OPERATION = new CRLReasonExtension(
+ RevocationReason.CESSATION_OF_OPERATION);
+ public static final CRLReasonExtension CERTIFICATE_HOLD = new CRLReasonExtension(RevocationReason.CERTIFICATE_HOLD);
+ public static final CRLReasonExtension REMOVE_FROM_CRL = new CRLReasonExtension(RevocationReason.REMOVE_FROM_CRL);
+ public static final CRLReasonExtension PRIVILEGE_WITHDRAWN = new CRLReasonExtension(
+ RevocationReason.PRIVILEGE_WITHDRAWN);
+ public static final CRLReasonExtension AA_COMPROMISE = new CRLReasonExtension(RevocationReason.AA_COMPROMISE);
+
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "CRLReason";
+ public static final String REASON = "value";
+
+ private RevocationReason mReason = null;
+
+ public RevocationReason getReason() {
+ return mReason;
+ }
+
+ /**
+ * Default constructor
+ *
+ */
+
+ public CRLReasonExtension() {
+ this.extensionId = PKIXExtensions.ReasonCode_Id;
+ this.critical = false;
+ mReason = null;
+ }
+
+ /**
+ * Create extension value for specific revocation reason
+ *
+ */
+
+ public CRLReasonExtension(RevocationReason reason) {
+ this.extensionId = PKIXExtensions.ReasonCode_Id;
+ this.critical = false;
+ mReason = reason;
+ }
+
+ public CRLReasonExtension(Boolean critical, RevocationReason reason)
+ throws IOException {
+ this.extensionId = PKIXExtensions.ReasonCode_Id;
+ this.critical = critical.booleanValue();
+ mReason = reason;
+ }
+
+ /**
+ * Create the object from the passed DER encoded value.
+ *
+ * @param derVal the DerValue decoded from the stream.
+ * @exception IOException on decoding errors.
+ */
+ public CRLReasonExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.ReasonCode_Id;
+ this.critical = critical.booleanValue();
+
+ byte[] extValue = (byte[]) ((byte[]) value).clone();
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ int reasonCode = val.getEnumerated();
+ mReason = RevocationReason.fromInt(reasonCode);
+ if (mReason == null)
+ throw new IOException("Unknown revocation reason value " + reasonCode);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof RevocationReason)) {
+ throw new IOException("Attribute must be of type RevocationReason.");
+ }
+
+ if (name.equalsIgnoreCase(REASON)) {
+ mReason = (RevocationReason) obj;
+ } else {
+ throw new IOException("Name not recognized by CRLReason");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(REASON)) {
+ return mReason;
+ } else {
+ throw new IOException("Name not recognized by CRLReason");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(REASON)) {
+ mReason = null;
+ } else {
+ throw new IOException("Name not recognized by CRLReason");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the ReasonFlags.
+ */
+ public String toString() {
+ String s = super.toString() + "CRL Reason [" + mReason + "]\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ if (mReason == null)
+ throw new IOException("Unintialized CRLReason extension");
+ DerOutputStream os = new DerOutputStream();
+ os.putEnumerated(mReason.toInt());
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(REASON);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ else if (other instanceof CRLReasonExtension)
+ return ((CRLReasonExtension) other).mReason == mReason &&
+ ((CRLReasonExtension) other).critical == critical;
+ else
+ return false;
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/CertAndKeyGen.java b/base/util/src/netscape/security/x509/CertAndKeyGen.java
new file mode 100644
index 000000000..1579d46bf
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertAndKeyGen.java
@@ -0,0 +1,290 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import netscape.security.pkcs.PKCS10;
+
+/**
+ * Generate a pair of keys, and provide access to them. This class is
+ * provided primarily for ease of use.
+ *
+ * <P>
+ * This provides some simple certificate management functionality. Specifically, it allows you to create self-signed
+ * X.509 certificates as well as PKCS 10 based certificate signing requests.
+ *
+ * <P>
+ * Keys for some public key signature algorithms have algorithm parameters, such as DSS/DSA. Some sites' Certificate
+ * Authorities adopt fixed algorithm parameters, which speeds up some operations including key generation and signing.
+ * <em>At this time, this interface
+ * does not provide a way to provide such algorithm parameters, e.g.
+ * by providing the CA certificate which includes those parameters.</em>
+ *
+ * <P>
+ * Also, note that at this time only signature-capable keys may be acquired through this interface. Diffie-Hellman keys,
+ * used for secure key exchange, may be supported later.
+ *
+ * @author David Brownell
+ * @author Hemma Prafullchandra
+ * @version 1.44
+ * @see PKCS10
+ * @see X509CertImpl
+ */
+public final class CertAndKeyGen {
+ /**
+ * Creates a CertAndKeyGen object for a particular key type
+ * and signature algorithm.
+ *
+ * @param keyType type of key, e.g. "RSA", "DSA"
+ * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
+ * "MD2WithRSA", "SHAwithDSA".
+ * @exception NoSuchAlgorithmException on unrecognized algorithms.
+ */
+ public CertAndKeyGen(String keyType, String sigAlg)
+ throws NoSuchAlgorithmException {
+ keyGen = KeyPairGenerator.getInstance(keyType);
+ this.sigAlg = sigAlg;
+ }
+
+ /**
+ * Sets the source of random numbers used when generating keys.
+ * If you do not provide one, a system default facility is used.
+ * You may wish to provide your own source of random numbers
+ * to get a reproducible sequence of keys and signatures, or
+ * because you may be able to take advantage of strong sources
+ * of randomness/entropy in your environment.
+ *
+ * @deprecated All random numbers come from PKCS #11 now.
+ */
+ public void setRandom(SecureRandom generator) {
+ }
+
+ // want "public void generate (X509Certificate)" ... inherit DSA/D-H param
+
+ /**
+ * Generates a random public/private key pair, with a given key
+ * size. Different algorithms provide different degrees of security
+ * for the same key size, because of the "work factor" involved in
+ * brute force attacks. As computers become faster, it becomes
+ * easier to perform such attacks. Small keys are to be avoided.
+ *
+ * <P>
+ * Note that not all values of "keyBits" are valid for all algorithms, and not all public key algorithms are
+ * currently supported for use in X.509 certificates. If the algorithm you specified does not produce X.509
+ * compatible keys, an invalid key exception is thrown.
+ *
+ * @param keyBits the number of bits in the keys.
+ * @exception InvalidKeyException if the environment does not
+ * provide X.509 public keys for this signature algorithm.
+ */
+ public void generate(int keyBits)
+ throws InvalidKeyException {
+ KeyPair pair;
+
+ try {
+ keyGen.initialize(keyBits);
+ pair = keyGen.generateKeyPair();
+
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+
+ PublicKey publicKey = pair.getPublic();
+
+ if (publicKey instanceof X509Key) {
+ this.publicKey = (X509Key) publicKey;
+
+ } else {
+ throw new InvalidKeyException("public key " + publicKey +
+ " not an X509Key.");
+ }
+ privateKey = pair.getPrivate();
+ }
+
+ /**
+ * Returns the public key of the generated key pair.
+ */
+ public X509Key getPublicKey() {
+ return publicKey;
+ }
+
+ /**
+ * Returns the private key of the generated key pair.
+ *
+ * <P>
+ * <STRONG><em>Be extremely careful when handling private keys.
+ * When private keys are not kept secret, they lose their ability
+ * to securely authenticate specific entities ... that is a huge
+ * security risk!</em></STRONG>
+ */
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ /**
+ * Returns a self-signed X.509v1 certificate for the public key.
+ * The certificate is immediately valid.
+ *
+ * <P>
+ * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always
+ * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security
+ * infrastructure, or deploying system prototypes.
+ *
+ * @deprecated Use the new <a href =
+ * "#getSelfCertificate(netscape.security.x509.X500Name, long)">
+ *
+ * @param myname X.500 name of the subject (who is also the issuer)
+ * @param validity how long the certificate should be valid, in seconds
+ */
+ public X509Cert getSelfCert(X500Name myname, long validity)
+ throws InvalidKeyException, SignatureException, NoSuchAlgorithmException {
+ X509Certificate cert;
+
+ try {
+ cert = getSelfCertificate(myname, validity);
+ return new X509Cert(cert.getEncoded());
+ } catch (CertificateException e) {
+ throw new SignatureException(e.getMessage());
+ } catch (NoSuchProviderException e) {
+ throw new NoSuchAlgorithmException(e.getMessage());
+ } catch (IOException e) {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a self-signed X.509v3 certificate for the public key.
+ * The certificate is immediately valid. No extensions.
+ *
+ * <P>
+ * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always
+ * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security
+ * infrastructure, or deploying system prototypes.
+ *
+ * @param myname X.500 name of the subject (who is also the issuer)
+ * @param validity how long the certificate should be valid, in seconds
+ * @exception CertificateException on certificate handling errors.
+ * @exception InvalidKeyException on key handling errors.
+ * @exception SignatureException on signature handling errors.
+ * @exception NoSuchAlgorithmException on unrecognized algorithms.
+ * @exception NoSuchProviderException on unrecognized providers.
+ */
+ public X509Certificate getSelfCertificate(X500Name myname, long validity)
+ throws CertificateException, InvalidKeyException, SignatureException,
+ NoSuchAlgorithmException, NoSuchProviderException {
+ X500Signer issuer;
+ X509CertImpl cert;
+ Date firstDate, lastDate;
+
+ try {
+ issuer = getSigner(myname);
+
+ firstDate = new Date();
+ lastDate = new Date();
+ lastDate.setTime(lastDate.getTime() + validity * 1000);
+
+ CertificateValidity interval =
+ new CertificateValidity(firstDate, lastDate);
+
+ X509CertInfo info = new X509CertInfo();
+ // Add all mandatory attributes
+ info.set(X509CertInfo.VERSION,
+ new CertificateVersion(CertificateVersion.V1));
+ info.set(X509CertInfo.SERIAL_NUMBER,
+ new CertificateSerialNumber((int) (firstDate.getTime() / 1000)));
+ AlgorithmId algID = issuer.getAlgorithmId();
+ info.set(X509CertInfo.ALGORITHM_ID,
+ new CertificateAlgorithmId(algID));
+ info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(myname));
+ info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
+ info.set(X509CertInfo.VALIDITY, interval);
+ info.set(X509CertInfo.ISSUER,
+ new CertificateIssuerName(issuer.getSigner()));
+
+ cert = new X509CertImpl(info);
+ cert.sign(privateKey, algID.getName());
+
+ return (X509Certificate) cert;
+
+ } catch (IOException e) {
+ throw new CertificateEncodingException("getSelfCert: " +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a PKCS #10 certificate request. The caller uses either <code>PKCS10.print</code> or
+ * <code>PKCS10.toByteArray</code> operations on the result, to get the request in an appropriate
+ * transmission format.
+ *
+ * <P>
+ * PKCS #10 certificate requests are sent, along with some proof of identity, to Certificate Authorities (CAs) which
+ * then issue X.509 public key certificates.
+ *
+ * @param myname X.500 name of the subject
+ * @exception InvalidKeyException on key handling errors.
+ * @exception SignatureException on signature handling errors.
+ */
+ public PKCS10 getCertRequest(X500Name myname)
+ throws InvalidKeyException, SignatureException {
+ PKCS10 req = new PKCS10(publicKey);
+
+ try {
+ req.encodeAndSign(getSigner(myname));
+
+ } catch (CertificateException e) {
+ throw new SignatureException(sigAlg + " CertificateException");
+
+ } catch (IOException e) {
+ throw new SignatureException(sigAlg + " IOException");
+
+ } catch (NoSuchAlgorithmException e) {
+ // "can't happen"
+ throw new SignatureException(sigAlg + " unavailable?");
+ }
+ return req;
+ }
+
+ private X500Signer getSigner(X500Name me)
+ throws InvalidKeyException, NoSuchAlgorithmException {
+ Signature signature = Signature.getInstance(sigAlg);
+
+ signature.initSign(privateKey);
+ return new X500Signer(signature, me);
+ }
+
+ private String sigAlg;
+ private KeyPairGenerator keyGen;
+ private X509Key publicKey;
+ private PrivateKey privateKey;
+}
diff --git a/base/util/src/netscape/security/x509/CertAttrSet.java b/base/util/src/netscape/security/x509/CertAttrSet.java
new file mode 100755
index 000000000..7e8d6db82
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertAttrSet.java
@@ -0,0 +1,120 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+
+/**
+ * This interface defines the methods required of a certificate attribute.
+ * Examples of X.509 certificate attributes are Validity, Issuer_Name, and
+ * Subject Name. A CertAttrSet may compromise one attribute or many
+ * attributes.
+ * <p>
+ * A CertAttrSet itself can also be comprised of other sub-sets. In the case of X.509 V3 certificates, for example, the
+ * "extensions" attribute has subattributes, such as those for KeyUsage and AuthorityKeyIdentifier.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ * @see CertificateException
+ */
+public interface CertAttrSet {
+ /**
+ * Returns a short string describing this certificate attribute.
+ *
+ * @return value of this certificate attribute in
+ * printable form.
+ */
+ String toString();
+
+ /**
+ * Encodes the attribute to the output stream in a format
+ * that can be parsed by the <code>decode</code> method.
+ *
+ * @param out the OutputStream to encode the attribute to.
+ *
+ * @exception CertificateException on encoding or validity errors.
+ * @exception IOException on other errors.
+ */
+ void encode(OutputStream out)
+ throws CertificateException, IOException;
+
+ /**
+ * Decodes the attribute in the input stream.
+ *
+ * @param in the InputStream to read the encoded attribute from.
+ *
+ * @exception CertificateException on decoding or validity errors.
+ * @exception IOException on other errors.
+ */
+ void decode(InputStream in)
+ throws CertificateException, IOException;
+
+ /**
+ * Sets an attribute value within this CertAttrSet.
+ *
+ * @param name the name of the attribute (e.g. "x509.info.key")
+ * @param obj the attribute object.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ void set(String name, Object obj)
+ throws CertificateException, IOException;
+
+ /**
+ * Gets an attribute value for this CertAttrSet.
+ *
+ * @param name the name of the attribute to return.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ Object get(String name)
+ throws CertificateException, IOException;
+
+ /**
+ * Deletes an attribute value from this CertAttrSet.
+ *
+ * @param name the name of the attribute to delete.
+ *
+ * @exception CertificateException on attribute handling errors.
+ * @exception IOException on other errors.
+ */
+ void delete(String name)
+ throws CertificateException, IOException;
+
+ /**
+ * Returns an enumeration of the names of the attributes existing within
+ * this attribute.
+ *
+ * @return an enumeration of the attribute names.
+ */
+ Enumeration<String> getAttributeNames();
+
+ /**
+ * Returns the name (identifier) of this CertAttrSet.
+ *
+ * @return the name of this CertAttrSet.
+ */
+ String getName();
+}
diff --git a/base/util/src/netscape/security/x509/CertException.java b/base/util/src/netscape/security/x509/CertException.java
new file mode 100644
index 000000000..31d9e686e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertException.java
@@ -0,0 +1,165 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+/**
+ * CertException indicates one of a variety of certificate problems.
+ *
+ * @version 1.18
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class CertException extends SecurityException {
+
+ // Zero is reserved.
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4046189948107720588L;
+
+ /** Indicates that the signature in the certificate is not valid. */
+ public static final int verf_INVALID_SIG = 1;
+
+ /** Indicates that the certificate was revoked, and so is invalid. */
+ public static final int verf_INVALID_REVOKED = 2;
+
+ /** Indicates that the certificate is not yet valid. */
+ public static final int verf_INVALID_NOTBEFORE = 3;
+
+ /** Indicates that the certificate has expired and so is not valid. */
+ public static final int verf_INVALID_EXPIRED = 4;
+
+ /**
+ * Indicates that a certificate authority in the certification
+ * chain is not trusted.
+ */
+ public static final int verf_CA_UNTRUSTED = 5;
+
+ /** Indicates that the certification chain is too long. */
+ public static final int verf_CHAIN_LENGTH = 6;
+
+ /** Indicates an error parsing the ASN.1/DER encoding of the certificate. */
+ public static final int verf_PARSE_ERROR = 7;
+
+ /** Indicates an error constructing a certificate or certificate chain. */
+ public static final int err_CONSTRUCTION = 8;
+
+ /** Indicates a problem with the public key */
+ public static final int err_INVALID_PUBLIC_KEY = 9;
+
+ /** Indicates a problem with the certificate version */
+ public static final int err_INVALID_VERSION = 10;
+
+ /** Indicates a problem with the certificate format */
+ public static final int err_INVALID_FORMAT = 11;
+
+ /** Indicates a problem with the certificate encoding */
+ public static final int err_ENCODING = 12;
+
+ // Private data members
+ private int verfCode;
+ private String moreData;
+
+ /**
+ * Constructs a certificate exception using an error code
+ * (<code>verf_*</code>) and a string describing the context
+ * of the error.
+ */
+ public CertException(int code, String moredata) {
+ verfCode = code;
+ moreData = moredata;
+ }
+
+ /**
+ * Constructs a certificate exception using just an error code,
+ * without a string describing the context.
+ */
+ public CertException(int code) {
+ verfCode = code;
+ }
+
+ /**
+ * Returns the error code with which the exception was created.
+ */
+ public int getVerfCode() {
+ return verfCode;
+ }
+
+ /**
+ * Returns a string describing the context in which the exception
+ * was reported.
+ */
+ public String getMoreData() {
+ return moreData;
+ }
+
+ /**
+ * Return a string corresponding to the error code used to create
+ * this exception.
+ */
+ public String getVerfDescription() {
+ switch (verfCode) {
+ case verf_INVALID_SIG:
+ return "The signature in the certificate is not valid.";
+ case verf_INVALID_REVOKED:
+ return "The certificate has been revoked.";
+ case verf_INVALID_NOTBEFORE:
+ return "The certificate is not yet valid.";
+ case verf_INVALID_EXPIRED:
+ return "The certificate has expired.";
+ case verf_CA_UNTRUSTED:
+ return "The Authority which issued the certificate is not trusted.";
+ case verf_CHAIN_LENGTH:
+ return "The certificate path to a trusted authority is too long.";
+ case verf_PARSE_ERROR:
+ return "The certificate could not be parsed.";
+ case err_CONSTRUCTION:
+ return "There was an error when constructing the certificate.";
+ case err_INVALID_PUBLIC_KEY:
+ return "The public key was not in the correct format.";
+ case err_INVALID_VERSION:
+ return "The certificate has an invalid version number.";
+ case err_INVALID_FORMAT:
+ return "The certificate has an invalid format.";
+ case err_ENCODING:
+ return "Problem encountered while encoding the data.";
+
+ default:
+ return "Unknown code: " + verfCode;
+ }
+ }
+
+ /**
+ * Returns a string describing the certificate exception.
+ */
+ public String toString() {
+ return "[Certificate Exception: " + getMessage() + "]";
+ }
+
+ /**
+ * Returns a string describing the certificate exception.
+ */
+ public String getMessage() {
+ return getVerfDescription()
+ + ((moreData != null)
+ ? ("\n (" + moreData + ")") : "");
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertParseError.java b/base/util/src/netscape/security/x509/CertParseError.java
new file mode 100644
index 000000000..7328c7207
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertParseError.java
@@ -0,0 +1,40 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+//back out these changes until backwards compatibility with
+//CertException is not an issue.
+//import java.security.CertificateException;
+
+/**
+ * CertException indicates one of a variety of certificate problems.
+ *
+ * @version 1.7
+ * @author David Brownell
+ */
+
+class CertParseError extends CertException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7623327377774730807L;
+
+ CertParseError(String where) {
+ super(CertException.verf_PARSE_ERROR, where);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateAlgorithmId.java b/base/util/src/netscape/security/x509/CertificateAlgorithmId.java
new file mode 100644
index 000000000..41610844e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateAlgorithmId.java
@@ -0,0 +1,189 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the AlgorithmId for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ */
+public class CertificateAlgorithmId implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6084780721443376563L;
+
+ private AlgorithmId algId;
+
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.algorithmID";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "algorithmID";
+ public static final String ALGORITHM = "algorithm";
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param algId the Algorithm identifier
+ */
+ public CertificateAlgorithmId(AlgorithmId algId) {
+ this.algId = algId;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the serial number from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateAlgorithmId(DerInputStream in) throws IOException {
+ DerValue val = in.getDerValue();
+ algId = AlgorithmId.parse(val);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the serial number from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateAlgorithmId(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ algId = AlgorithmId.parse(val);
+ }
+
+ /**
+ * Return the algorithm identifier as user readable string.
+ */
+ public String toString() {
+ if (algId == null)
+ return "";
+ return (algId.toString() +
+ ", OID = " + (algId.getOID()).toString() + "\n");
+ }
+
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws IOException {
+ encode(stream);
+ }
+
+ private synchronized void readObject(ObjectInputStream stream)
+ throws IOException {
+ decode(stream);
+ }
+
+ /**
+ * Encode the algorithm identifier in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ algId.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the algorithm identifier from the passed stream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ algId = AlgorithmId.parse(derVal);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof AlgorithmId)) {
+ throw new IOException("Attribute must be of type AlgorithmId.");
+ }
+ if (name.equalsIgnoreCase(ALGORITHM)) {
+ algId = (AlgorithmId) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateAlgorithmId.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(ALGORITHM)) {
+ return (algId);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateAlgorithmId.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(ALGORITHM)) {
+ algId = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateAlgorithmId.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(ALGORITHM);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateChain.java b/base/util/src/netscape/security/x509/CertificateChain.java
new file mode 100644
index 000000000..b60325378
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateChain.java
@@ -0,0 +1,137 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.cert.X509Certificate;
+
+import netscape.security.pkcs.ContentInfo;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.pkcs.SignerInfo;
+
+public class CertificateChain implements Serializable {
+ public CertificateChain() {
+ }
+
+ /**
+ * constructs a certificate chain from a certificate.
+ *
+ * @param cert a certificate
+ */
+ public CertificateChain(X509Certificate cert) {
+ mChain = new X509Certificate[1];
+ mChain[0] = cert;
+ }
+
+ /**
+ * constructs a certificate chain from a X509 certificate array.
+ *
+ * @param chain a certificate array.
+ */
+ public CertificateChain(X509Certificate[] chain) {
+ mChain = (X509Certificate[]) chain.clone();
+ }
+
+ /**
+ * returns the certificate at specified index in chain.
+ *
+ * @param index the index.
+ * @return the X509 certificate at the given index.
+ */
+ public X509Certificate getCertificate(int index) {
+ return mChain[index];
+ }
+
+ /**
+ * returns the first certificate in chain.
+ *
+ * @return the X509 certificate at the given index.
+ */
+ public X509Certificate getFirstCertificate() {
+ return mChain[0];
+ }
+
+ /**
+ * returns the certificate chain as an array of X509 certificates.
+ *
+ * @return an array of X509 Certificates.
+ */
+ public X509Certificate[] getChain() {
+ return (X509Certificate[]) mChain.clone();
+ }
+
+ public void encode(OutputStream out)
+ throws IOException {
+ encode(out, true);
+ }
+
+ /**
+ * encode in PKCS7 blob.
+ */
+ public void encode(OutputStream out, boolean sort)
+ throws IOException {
+ PKCS7 p7 = new PKCS7(new AlgorithmId[0],
+ new ContentInfo(new byte[0]), mChain,
+ new SignerInfo[0]);
+ p7.encodeSignedData(out, sort);
+ }
+
+ /**
+ * decode from PKCS7 blob.
+ */
+ public void decode(InputStream in)
+ throws IOException {
+ PKCS7 p7 = new PKCS7(in);
+ mChain = p7.getCertificates();
+ }
+
+ /**
+ * for serialization
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ encode(out);
+ }
+
+ /**
+ * for serialization
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException {
+ decode(in);
+ }
+
+ /**
+ * Converts the certificate chain to a readable string.
+ */
+ public String toString() {
+ String s = "[\n";
+ if (mChain == null)
+ return "[empty]";
+ for (int i = 0; i < mChain.length; i++) {
+ s += mChain[i].toString();
+ }
+ s += "]\n";
+ return s;
+ }
+
+ private X509Certificate[] mChain = null;
+}
diff --git a/base/util/src/netscape/security/x509/CertificateExtensions.java b/base/util/src/netscape/security/x509/CertificateExtensions.java
new file mode 100644
index 000000000..b9667d8f6
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateExtensions.java
@@ -0,0 +1,276 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the Extensions attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.11
+ * @see CertAttrSet
+ */
+public class CertificateExtensions extends Vector<Extension>
+ implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7172635300185788849L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions";
+ /**
+ * name
+ */
+ public static final String NAME = "extensions";
+
+ private Hashtable<String, Extension> map;
+
+ // Parse the encoded extension
+ public void parseExtension(Extension ext) throws IOException {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<CertAttrSet> extClass = (Class<CertAttrSet>) OIDMap.getClass(ext.getExtensionId());
+ if (extClass == null) { // Unsupported extension
+ if (ext.isCritical()) {
+ throw new IOException("Unsupported CRITICAL extension: "
+ + ext.getExtensionId());
+ } else {
+ map.put(ext.getExtensionId().toString(), ext);
+ addElement(ext);
+ return;
+ }
+ }
+ Class<?>[] params = { Boolean.class, Object.class };
+ Constructor<CertAttrSet> cons = extClass.getConstructor(params);
+
+ byte[] extData = ext.getExtensionValue();
+ int extLen = extData.length;
+ Object value = Array.newInstance(byte.class, extLen);
+
+ for (int i = 0; i < extLen; i++) {
+ Array.setByte(value, i, extData[i]);
+ }
+ Object[] passed = new Object[] { new Boolean(ext.isCritical()),
+ value };
+ CertAttrSet certExt = cons.newInstance(passed);
+ if (certExt != null && certExt.getName() != null) {
+ map.put(certExt.getName(), (Extension) certExt);
+ addElement((Extension) certExt);
+ }
+ } catch (NoSuchMethodException nosuch) {
+ throw new IOException(nosuch.toString());
+ } catch (InvocationTargetException invk) {
+ throw new IOException(invk.getTargetException().toString());
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+
+ /**
+ * Default constructor for the certificate attribute.
+ */
+ public CertificateExtensions() {
+ map = new Hashtable<String, Extension>();
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the Extension from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateExtensions(DerInputStream in)
+ throws IOException {
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = in.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ }
+
+ /**
+ * Decode the extensions from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ DerInputStream str = val.toDerInputStream();
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = str.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ }
+
+ /**
+ * Decode the extensions from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decodeEx(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ DerInputStream str = null;
+ if (val.isConstructed() && val.isContextSpecific((byte) 3)) {
+ str = val.data;
+ } else {
+ str = val.toDerInputStream();
+ }
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = str.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ }
+
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws CertificateException, IOException {
+ encode(stream);
+ }
+
+ private synchronized void readObject(ObjectInputStream stream)
+ throws CertificateException, IOException {
+ decodeEx(stream);
+ }
+
+ /**
+ * Encode the extensions in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception CertificateException on encoding errors.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ DerOutputStream extOut = new DerOutputStream();
+ for (int i = 0; i < size(); i++) {
+ Object thisOne = elementAt(i);
+ if (thisOne instanceof CertAttrSet)
+ ((CertAttrSet) thisOne).encode(extOut);
+ else if (thisOne instanceof Extension)
+ ((Extension) thisOne).encode(extOut);
+ else
+ throw new CertificateException("Invalid extension object");
+ }
+
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.tag_Sequence, extOut);
+
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3),
+ seq);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ *
+ * @param name the extension name used in the cache.
+ * @param obj the object to set.
+ * @exception IOException if the object could not be cached.
+ */
+ public void set(String name, Object obj) throws IOException {
+ map.put(name, (Extension) obj);
+ addElement((Extension) obj);
+ }
+
+ /**
+ * Get the attribute value.
+ *
+ * @param name the extension name used in the lookup.
+ * @exception IOException if named extension is not found.
+ */
+ public Object get(String name) throws IOException {
+ Object obj = map.get(name);
+ if (obj == null) {
+ throw new IOException("No extension found with name " + name);
+ }
+ return (obj);
+ }
+
+ /**
+ * Delete the attribute value.
+ *
+ * @param name the extension name used in the lookup.
+ * @exception IOException if named extension is not found.
+ */
+ public void delete(String name) throws IOException {
+ Object obj = map.get(name);
+ if (obj == null) {
+ throw new IOException("No extension found with name " + name);
+ }
+ map.remove(name);
+ removeElement(obj);
+ }
+
+ public Enumeration<String> getNames() {
+ return map.keys();
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<Extension> getAttributes() {
+ return (map.elements());
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ return (map.keys());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateIssuerExtension.java b/base/util/src/netscape/security/x509/CertificateIssuerExtension.java
new file mode 100644
index 000000000..774116bcc
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateIssuerExtension.java
@@ -0,0 +1,242 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CRL Certificate Issuer Extension.
+ *
+ * <p>
+ * This CRL entry extension identifies the certificate issuer associated with an entry in an indirect CRL, i.e. a CRL
+ * that has the indirectCRL indicator set in its issuing distribution point extension.
+ *
+ * @see Extension
+ * @see CertAttrSet
+ */
+
+public class CertificateIssuerExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8643788952936025986L;
+ /**
+ * Attribute name.
+ */
+ public static final String NAME = "CertificateIssuer";
+ public static final String CERTIFICATE_ISSUER = "value";
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.29";
+
+ // private data members
+ GeneralNames names = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(CertificateIssuerExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ // Encode this extension
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ try {
+ names.encode(os);
+ } catch (GeneralNamesException e) {
+ throw new IOException(e.toString());
+ }
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a CertificateIssuerExtension with the passed GeneralNames
+ * and criticality.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param names the GeneralNames for the issuer.
+ * @exception IOException on error.
+ */
+ public CertificateIssuerExtension(Boolean critical, GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.CertificateIssuer_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create a CertificateIssuerExtension with the passed GeneralNames.
+ *
+ * @param names the GeneralNames for the issuer.
+ * @exception IOException on error.
+ */
+ public CertificateIssuerExtension(GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.CertificateIssuer_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create a default CertificateIssuerExtension.
+ */
+ public CertificateIssuerExtension() {
+ extensionId = PKIXExtensions.CertificateIssuer_Id;
+ critical = false;
+ names = new GeneralNames();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public CertificateIssuerExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.CertificateIssuer_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ try {
+ names = new GeneralNames(val);
+ } catch (GeneralNamesException e) {
+ throw new IOException("CertificateIssuerExtension: " +
+ e.toString());
+ }
+ }
+
+ /**
+ * Returns a printable representation of the CertificateIssuerName.
+ */
+ public String toString() {
+ if (names == null)
+ return "";
+ String s = super.toString() + "CertificateIssuerName [\n"
+ + names.toString() + "]\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding error.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.CertificateIssuer_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) {
+ if (!(obj instanceof GeneralNames)) {
+ throw new IOException("Attribute value should be of" +
+ " type GeneralNames.");
+ }
+ names = (GeneralNames) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) {
+ return (names);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) {
+ names = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(CERTIFICATE_ISSUER);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateIssuerName.java b/base/util/src/netscape/security/x509/CertificateIssuerName.java
new file mode 100644
index 000000000..a2f9026c1
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateIssuerName.java
@@ -0,0 +1,172 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the X500Name attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ * @see CertAttrSet
+ */
+public class CertificateIssuerName implements CertAttrSet {
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.issuer";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "issuer";
+ public static final String DN_NAME = "dname";
+
+ // Private data member
+ private X500Name dnName;
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param name the X500Name
+ */
+ public CertificateIssuerName(X500Name name) {
+ this.dnName = name;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the X500Name from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateIssuerName(DerInputStream in) throws IOException {
+ dnName = new X500Name(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the X500Name from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateIssuerName(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ dnName = new X500Name(derVal);
+ }
+
+ /**
+ * Return the name as user readable string.
+ */
+ public String toString() {
+ if (dnName == null)
+ return "";
+ return (dnName.toString());
+ }
+
+ /**
+ * Encode the name in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ dnName.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the name in DER form from the stream.
+ *
+ * @param in the InputStream to marshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ dnName = new X500Name(derVal);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof X500Name)) {
+ throw new IOException("Attribute must be of type X500Name.");
+ }
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ this.dnName = (X500Name) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ return (dnName);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ dnName = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateIssuerName.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(DN_NAME);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateIssuerUniqueIdentity.java b/base/util/src/netscape/security/x509/CertificateIssuerUniqueIdentity.java
new file mode 100644
index 000000000..351116ffb
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateIssuerUniqueIdentity.java
@@ -0,0 +1,185 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the subject/issuer unique identity attribute
+ * for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ * @see CertAttrSet
+ */
+public class CertificateIssuerUniqueIdentity implements CertAttrSet {
+ private UniqueIdentity id;
+
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.issuerID";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "issuerID";
+ public static final String ID = "id";
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param key the UniqueIdentity
+ */
+ public CertificateIssuerUniqueIdentity(UniqueIdentity id) {
+ this.id = id;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateIssuerUniqueIdentity(DerInputStream in)
+ throws IOException {
+ id = new UniqueIdentity(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateIssuerUniqueIdentity(InputStream in)
+ throws IOException {
+ DerValue val = new DerValue(in);
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER value.
+ *
+ * @param in the DerValue to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateIssuerUniqueIdentity(DerValue val)
+ throws IOException {
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Return the identity as user readable string.
+ */
+ public String toString() {
+ if (id == null)
+ return "";
+ return (id.toString());
+ }
+
+ /**
+ * Decode the identity in DER form from the stream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Encode the identity in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ id.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false, (byte) 1));
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof UniqueIdentity)) {
+ throw new IOException("Attribute must be of type UniqueIdentity.");
+ }
+ if (name.equalsIgnoreCase(ID)) {
+ id = (UniqueIdentity) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateIssuerUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(ID)) {
+ return (id);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateIssuerUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(ID)) {
+ id = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateIssuerUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(ID);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificatePoliciesExtension.java b/base/util/src/netscape/security/x509/CertificatePoliciesExtension.java
new file mode 100644
index 000000000..fedc15917
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificatePoliciesExtension.java
@@ -0,0 +1,338 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * This class defines the Certificate Policies Extension.
+ *
+ * <p>
+ * The certificate policies extension conatins a sequence of policy information terms, each of which consists of an
+ * object identifier (OID) and optional qualifiers. These policy information terms indicate the policy under which the
+ * certificate has been issued and the purposes for which the certificate may be used. Aplications with specific policy
+ * requirements are expected to have a list of those policies which they will accept and to compare the policy OIDs in
+ * the certificate to that list. If this extension is critical, the path validation software must be able to interpret
+ * this extension, or must reject the certificate.
+ *
+ * <pre>
+ * CertificatePolicies ::= SEQUENECE OF PolicyInformation
+ * </pre>
+ *
+ * @author Christine Ho
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class CertificatePoliciesExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3729294064061837367L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.CertificatePolicies";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "CertificatePolicies";
+ public static final String INFOS = "infos";
+
+ // Private data members
+ private Vector<CertificatePolicyInfo> mInfos;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < mInfos.size(); i++) {
+ ((CertificatePolicyInfo) mInfos.elementAt(i)).encode(tmp);
+ }
+ os.write(DerValue.tag_Sequence, tmp);
+ extensionValue = os.toByteArray();
+ }
+
+ public CertificatePoliciesExtension(boolean critical, Vector<CertificatePolicyInfo> infos) throws IOException {
+ this.mInfos = infos;
+ this.extensionId = PKIXExtensions.CertificatePolicies_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create a CertificatePolicies with the Vector of CertificatePolicyInfo.
+ *
+ * @param infos the Vector of CertificatePolicyInfo.
+ */
+ public CertificatePoliciesExtension(Vector<CertificatePolicyInfo> infos) throws IOException {
+ this.mInfos = infos;
+ this.extensionId = PKIXExtensions.CertificatePolicies_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a default CertificatePoliciesExtension.
+ */
+ public CertificatePoliciesExtension() {
+ this.extensionId = PKIXExtensions.CertificatePolicies_Id;
+ critical = false;
+ mInfos = new Vector<CertificatePolicyInfo>(1, 1);
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public CertificatePoliciesExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.CertificatePolicies_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for " +
+ "CertificatePoliciesExtension.");
+ }
+ mInfos = new Vector<CertificatePolicyInfo>(1, 1);
+ while (val.data.available() != 0) {
+ DerValue seq = val.data.getDerValue();
+ CertificatePolicyInfo info = new CertificatePolicyInfo(seq);
+ mInfos.addElement(info);
+ }
+ }
+
+ /**
+ * Returns a printable representation of the policy extension.
+ */
+ public String toString() {
+ if (mInfos == null)
+ return "";
+ String s = super.toString() + "Certificate Policies [\n"
+ + mInfos.toString() + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.CertificatePolicies_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ @SuppressWarnings("unchecked")
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(INFOS)) {
+ if (!(obj instanceof Vector)) {
+ throw new IOException("Attribute value should be of" +
+ " type Vector.");
+ }
+ mInfos = (Vector<CertificatePolicyInfo>) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificatePoliciesExtension.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(INFOS)) {
+ return (mInfos);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificatePoliciesExtension.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(INFOS)) {
+ mInfos = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificatePoliciesExtension.");
+ }
+ }
+
+ /**
+ * Return an enumeration of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<Vector<CertificatePolicyInfo>> getAttributes() {
+ Vector<Vector<CertificatePolicyInfo>> elements = new Vector<Vector<CertificatePolicyInfo>>();
+ elements.addElement(mInfos);
+ return (elements.elements());
+ }
+
+ private static final String[] NAMES = { INFOS };
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ // TODO Auto-generated method stub
+ return Collections.enumeration(Arrays.asList(NAMES));
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ public static void main(String args[]) {
+
+ /**
+ * From ASN.1 dump
+ *
+ * 0 30 133: SEQUENCE {
+ * 3 30 45: . SEQUENCE {
+ * 5 06 3: . . OBJECT IDENTIFIER '1 2 3 5'
+ * 10 30 38: . . SEQUENCE {
+ * 12 30 36: . . . SEQUENCE {
+ * 14 06 8: . . . . OBJECT IDENTIFIER cps (1 3 6 1 5 5 7 2 1)
+ * : . . . . . (PKIX policy qualifier)
+ * 24 16 24: . . . . IA5String 'http://home.netscape.com'
+ * : . . . . }
+ * : . . . }
+ * : . . }
+ * 50 30 84: . SEQUENCE {
+ * 52 06 2: . . OBJECT IDENTIFIER '2 3 5'
+ * 56 30 78: . . SEQUENCE {
+ * 58 30 36: . . . SEQUENCE {
+ * 60 06 8: . . . . OBJECT IDENTIFIER cps (1 3 6 1 5 5 7 2 1)
+ * : . . . . . (PKIX policy qualifier)
+ * 70 16 24: . . . . IA5String 'http://home.netscape.com'
+ * : . . . . }
+ * 96 30 38: . . . SEQUENCE {
+ * 98 06 8: . . . . OBJECT IDENTIFIER unotice (1 3 6 1 5 5 7 2 2)
+ * : . . . . . (PKIX policy qualifier)
+ * 108 30 26: . . . . SEQUENCE {
+ * 110 30 16: . . . . . SEQUENCE {
+ * 112 1E 8: . . . . . . BMPString (1993) '_..o.r.g'
+ * 122 02 1: . . . . . . INTEGER 1
+ * 125 02 1: . . . . . . INTEGER 2
+ * : . . . . . . }
+ * 128 1E 6: . . . . . BMPString (1993) '_..d.t'
+ * : . . . . . }
+ * : . . . . }
+ * : . . . }
+ * : . . }
+ * : . }
+ **/
+
+ CertificatePolicyId plcyId0 = new CertificatePolicyId(
+ new ObjectIdentifier("1.2.3.5")
+ );
+ PolicyQualifiers qualifiers0 = new PolicyQualifiers();
+ CPSuri cpsQualifier0 = new CPSuri("http://home.netscape.com");
+ PolicyQualifierInfo qualifierInfo0 = new PolicyQualifierInfo(
+ PolicyQualifierInfo.QT_CPS,
+ cpsQualifier0
+ );
+ qualifiers0.add(qualifierInfo0);
+ CertificatePolicyInfo info0 = new CertificatePolicyInfo(
+ plcyId0, qualifiers0);
+ CertificatePolicyId plcyId1 = new CertificatePolicyId(
+ new ObjectIdentifier("2.3.5")
+ );
+ PolicyQualifiers qualifiers1 = new PolicyQualifiers();
+ DisplayText org1 = new DisplayText(DisplayText.tag_BMPString,
+ "org");
+ int nums[] = { 1, 2 };
+ NoticeReference nr1 = new NoticeReference(org1, nums);
+ DisplayText dt1 = new DisplayText(DisplayText.tag_BMPString,
+ "dt");
+ UserNotice userNotice1 = new UserNotice(nr1, dt1);
+ PolicyQualifierInfo qualifierInfo1 = new PolicyQualifierInfo(
+ PolicyQualifierInfo.QT_UNOTICE,
+ userNotice1
+ );
+ qualifiers1.add(qualifierInfo0);
+ qualifiers1.add(qualifierInfo1);
+ CertificatePolicyInfo info1 = new CertificatePolicyInfo(
+ plcyId1, qualifiers1);
+ Vector<CertificatePolicyInfo> infos = new Vector<CertificatePolicyInfo>();
+ infos.addElement(info0);
+ infos.addElement(info1);
+ try {
+ CertificatePoliciesExtension ext =
+ new CertificatePoliciesExtension(infos);
+
+ // BASE64 encode the whole thing and write it to stdout
+ System.out.println(Utils.base64encode(ext.getExtensionValue()));
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/CertificatePolicyId.java b/base/util/src/netscape/security/x509/CertificatePolicyId.java
new file mode 100644
index 000000000..bfc93b0bb
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificatePolicyId.java
@@ -0,0 +1,85 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Represent the CertificatePolicyId ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.5
+ */
+public class CertificatePolicyId implements java.io.Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2376810529862707757L;
+ private ObjectIdentifier id;
+
+ /**
+ * Create a CertificatePolicyId with the ObjectIdentifier.
+ *
+ * @param id the ObjectIdentifier for the policy id.
+ */
+ public CertificatePolicyId(ObjectIdentifier id) {
+ this.id = id;
+ }
+
+ /**
+ * Create the object from its Der encoded value.
+ *
+ * @param val the DER encoded value for the same.
+ */
+ public CertificatePolicyId(DerValue val) throws IOException {
+ this.id = val.getOID();
+ }
+
+ /**
+ * Return the value of the CertificatePolicyId as an ObjectIdentifier.
+ */
+ public ObjectIdentifier getIdentifier() {
+ return (id);
+ }
+
+ /**
+ * Returns a printable representation of the CertificatePolicyId.
+ */
+ public String toString() {
+ String s = "CertificatePolicyId: ["
+ + id.toString()
+ + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the CertificatePolicyId to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putOID(id);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificatePolicyInfo.java b/base/util/src/netscape/security/x509/CertificatePolicyInfo.java
new file mode 100644
index 000000000..33e541c65
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificatePolicyInfo.java
@@ -0,0 +1,110 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CertificatePolicyInformation ASN.1 object.
+ *
+ * @author Christine Ho
+ */
+public class CertificatePolicyInfo implements java.io.Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8516006396099280477L;
+ private CertificatePolicyId mPolicyIdentifier;
+ private PolicyQualifiers mPolicyQualifiers;
+
+ /**
+ * Create a CertificatePolicyInfo with the passed CertificatePolicyId's.
+ *
+ * @param id the CertificatePolicyId.
+ */
+ public CertificatePolicyInfo(CertificatePolicyId id) {
+ this.mPolicyIdentifier = id;
+ this.mPolicyQualifiers = null;
+ }
+
+ public CertificatePolicyInfo(CertificatePolicyId id, PolicyQualifiers qualifiers) {
+ this.mPolicyIdentifier = id;
+ this.mPolicyQualifiers = qualifiers;
+ }
+
+ /**
+ * Create the CertificatePolicyInfo from the DER encoded value.
+ *
+ * @param val the DER encoded value of the same.
+ */
+ public CertificatePolicyInfo(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for CertificatePolicyInfo");
+ }
+ mPolicyIdentifier = new CertificatePolicyId(val.data.getDerValue());
+ // The specification is not clear on whether qualifier is
+ // optional or not. GTE CyberTrust Root certificate has
+ // no qualifier.
+ if (val.data.available() == 0) {
+ mPolicyQualifiers = null;
+ } else {
+ mPolicyQualifiers = new PolicyQualifiers(val.data.getDerValue());
+ }
+ }
+
+ /**
+ * return the policy identifier of the policy info
+ */
+ public CertificatePolicyId getPolicyIdentifier() {
+ return (mPolicyIdentifier);
+ }
+
+ public PolicyQualifiers getPolicyQualifiers() {
+ return mPolicyQualifiers;
+ }
+
+ /**
+ * Returns a printable representation of the CertificatePolicyId.
+ */
+ public String toString() {
+ String s = "CertificatePolicyInfo: [\n"
+ + "PolicyIdentifier:" + mPolicyIdentifier.toString()
+
+ + "]\n";
+ return (s);
+ }
+
+ /**
+ * Write the CertificatePolicyInfo to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ mPolicyIdentifier.encode(tmp);
+ if (mPolicyQualifiers != null) {
+ mPolicyQualifiers.encode(tmp);
+ }
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificatePolicyMap.java b/base/util/src/netscape/security/x509/CertificatePolicyMap.java
new file mode 100644
index 000000000..75ddf3314
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificatePolicyMap.java
@@ -0,0 +1,100 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CertificatePolicyMap ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.5
+ */
+public class CertificatePolicyMap {
+ private CertificatePolicyId issuerDomain;
+ private CertificatePolicyId subjectDomain;
+
+ /**
+ * Create a CertificatePolicyMap with the passed CertificatePolicyId's.
+ *
+ * @param issuer the CertificatePolicyId for the issuer CA.
+ * @param subject the CertificatePolicyId for the subject CA.
+ */
+ public CertificatePolicyMap(CertificatePolicyId issuer,
+ CertificatePolicyId subject) {
+ this.issuerDomain = issuer;
+ this.subjectDomain = subject;
+ }
+
+ /**
+ * Create the CertificatePolicyMap from the DER encoded value.
+ *
+ * @param val the DER encoded value of the same.
+ */
+ public CertificatePolicyMap(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for CertificatePolicyMap");
+ }
+ issuerDomain = new CertificatePolicyId(val.data.getDerValue());
+ subjectDomain = new CertificatePolicyId(val.data.getDerValue());
+ }
+
+ /**
+ * Return the issuer CA part of the policy map.
+ */
+ public CertificatePolicyId getIssuerIdentifier() {
+ return (issuerDomain);
+ }
+
+ /**
+ * Return the subject CA part of the policy map.
+ */
+ public CertificatePolicyId getSubjectIdentifier() {
+ return (subjectDomain);
+ }
+
+ /**
+ * Returns a printable representation of the CertificatePolicyId.
+ */
+ public String toString() {
+ String s = "CertificatePolicyMap: [\n"
+ + "IssuerDomain:" + issuerDomain.toString()
+ + "SubjectDomain:" + subjectDomain.toString()
+ + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the CertificatePolicyMap to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ issuerDomain.encode(tmp);
+ subjectDomain.encode(tmp);
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificatePolicySet.java b/base/util/src/netscape/security/x509/CertificatePolicySet.java
new file mode 100644
index 000000000..86d9c107f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificatePolicySet.java
@@ -0,0 +1,86 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the certificate policy set ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class CertificatePolicySet {
+ private Vector<CertificatePolicyId> ids;
+
+ /**
+ * The default constructor for this class.
+ *
+ * @param ids the sequence of CertificatePolicyId's.
+ */
+ public CertificatePolicySet(Vector<CertificatePolicyId> ids) {
+ this.ids = ids;
+ }
+
+ /**
+ * Create the object from the DerValue.
+ *
+ * @param in the passed DerInputStream.
+ * @exception IOException on decoding errors.
+ */
+ public CertificatePolicySet(DerInputStream in) throws IOException {
+ ids = new Vector<CertificatePolicyId>(1, 1);
+ DerValue[] seq = in.getSequence(5);
+
+ for (int i = 0; i < seq.length; i++) {
+ CertificatePolicyId id = new CertificatePolicyId(seq[i]);
+ ids.addElement(id);
+ }
+ }
+
+ /**
+ * Return printable form of the object.
+ */
+ public String toString() {
+ String s = "CertificatePolicySet:[\n"
+ + ids.toString()
+ + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Encode the policy set to the output stream.
+ *
+ * @param out the DerOutputStream to encode the data to.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < ids.size(); i++) {
+ ((CertificatePolicyId) ids.elementAt(i)).encode(tmp);
+ }
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateSerialNumber.java b/base/util/src/netscape/security/x509/CertificateSerialNumber.java
new file mode 100644
index 000000000..e9655178f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateSerialNumber.java
@@ -0,0 +1,191 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the SerialNumber attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ * @see CertAttrSet
+ */
+public class CertificateSerialNumber implements CertAttrSet {
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.serialNumber";
+
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "serialNumber";
+ public static final String NUMBER = "number";
+
+ private SerialNumber serial;
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param serial the serial number for the certificate.
+ */
+ public CertificateSerialNumber(BigInteger num) {
+ this.serial = new SerialNumber(num);
+ }
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param serial the serial number for the certificate.
+ */
+ public CertificateSerialNumber(int num) {
+ this.serial = new SerialNumber(num);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the serial number from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSerialNumber(DerInputStream in) throws IOException {
+ serial = new SerialNumber(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the serial number from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSerialNumber(InputStream in) throws IOException {
+ serial = new SerialNumber(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DerValue.
+ *
+ * @param val the DER encoded value.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSerialNumber(DerValue val) throws IOException {
+ serial = new SerialNumber(val);
+ }
+
+ /**
+ * Return the serial number as user readable string.
+ */
+ public String toString() {
+ if (serial == null)
+ return "";
+ return (serial.toString());
+ }
+
+ /**
+ * Encode the serial number in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ serial.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the serial number in DER form from the stream.
+ *
+ * @param in the InputStream to marshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ serial = new SerialNumber(derVal);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof SerialNumber)) {
+ throw new IOException("Attribute must be of type SerialNumber.");
+ }
+ if (name.equalsIgnoreCase(NUMBER)) {
+ serial = (SerialNumber) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSerialNumber.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ return (serial);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSerialNumber.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ serial = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSerialNumber.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NUMBER);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateSubjectName.java b/base/util/src/netscape/security/x509/CertificateSubjectName.java
new file mode 100644
index 000000000..6159638b9
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateSubjectName.java
@@ -0,0 +1,203 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the X500Name attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ * @see CertAttrSet
+ */
+public class CertificateSubjectName implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 503643453152834350L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.subject";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "subject";
+ public static final String DN_NAME = "dname";
+
+ // Private data member
+ private X500Name dnName;
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param name the X500Name
+ */
+ public CertificateSubjectName(X500Name name) {
+ this.dnName = name;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the X500Name from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSubjectName(DerInputStream in) throws IOException {
+ dnName = new X500Name(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the X500Name from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSubjectName(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ dnName = new X500Name(derVal);
+ }
+
+ /**
+ * Return the name as user readable string.
+ */
+ public String toString() {
+ if (dnName == null)
+ return "";
+ return (dnName.toString());
+ }
+
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws IOException {
+ encode(stream);
+ }
+
+ private synchronized void readObject(ObjectInputStream stream)
+ throws IOException {
+ decodeEx(stream);
+ }
+
+ /**
+ * Encode the name in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ dnName.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the name in DER form from the stream.
+ *
+ * @param in the InputStream to marshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decodeEx(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+
+ // dnName = new X500Name(derVal);
+ dnName = new X500Name(derVal.toByteArray());
+ }
+
+ /**
+ * Decode the name in DER form from the stream.
+ *
+ * @param in the InputStream to marshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+
+ dnName = new X500Name(derVal);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof X500Name)) {
+ throw new IOException("Attribute must be of type X500Name.");
+ }
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ this.dnName = (X500Name) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSubjectName.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ return (dnName);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSubjectName.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(DN_NAME)) {
+ dnName = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:CertificateSubjectName.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(DN_NAME);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateSubjectUniqueIdentity.java b/base/util/src/netscape/security/x509/CertificateSubjectUniqueIdentity.java
new file mode 100644
index 000000000..51687e86d
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateSubjectUniqueIdentity.java
@@ -0,0 +1,185 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the subject/issuer unique identity attribute
+ * for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ * @see CertAttrSet
+ */
+public class CertificateSubjectUniqueIdentity implements CertAttrSet {
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.subjectID";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "subjectID";
+ public static final String ID = "id";
+
+ private UniqueIdentity id;
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param key the UniqueIdentity
+ */
+ public CertificateSubjectUniqueIdentity(UniqueIdentity id) {
+ this.id = id;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSubjectUniqueIdentity(DerInputStream in)
+ throws IOException {
+ id = new UniqueIdentity(in);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSubjectUniqueIdentity(InputStream in)
+ throws IOException {
+ DerValue val = new DerValue(in);
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER value.
+ *
+ * @param in the DerValue to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateSubjectUniqueIdentity(DerValue val)
+ throws IOException {
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Return the identity as user readable string.
+ */
+ public String toString() {
+ if (id == null)
+ return "";
+ return (id.toString());
+ }
+
+ /**
+ * Decode the identity in DER form from the stream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ id = new UniqueIdentity(val);
+ }
+
+ /**
+ * Encode the identity in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ id.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false, (byte) 2));
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof UniqueIdentity)) {
+ throw new IOException("Attribute must be of type UniqueIdentity.");
+ }
+ if (name.equalsIgnoreCase(ID)) {
+ id = (UniqueIdentity) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateSubjectUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(ID)) {
+ return (id);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateSubjectUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(ID)) {
+ id = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateSubjectUniqueIdentity.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(ID);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateValidity.java b/base/util/src/netscape/security/x509/CertificateValidity.java
new file mode 100644
index 000000000..0c2c841b0
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateValidity.java
@@ -0,0 +1,306 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the interval for which the certificate is valid.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.12
+ * @see CertAttrSet
+ */
+public class CertificateValidity implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8277703278213804194L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.validity";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "validity";
+ public static final String NOT_BEFORE = "notBefore";
+ public static final String NOT_AFTER = "notAfter";
+ private static final long YR_2050 = 2524636800000L;
+
+ // Private data members
+ private Date notBefore;
+ private Date notAfter;
+
+ // Returns the first time the certificate is valid.
+ private Date getNotBefore() {
+ return (new Date(notBefore.getTime()));
+ }
+
+ // Returns the last time the certificate is valid.
+ private Date getNotAfter() {
+ return (new Date(notAfter.getTime()));
+ }
+
+ // Construct the class from the DerValue
+ private void construct(DerValue derVal) throws IOException {
+ if (derVal.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoded CertificateValidity, " +
+ "starting sequence tag missing.");
+ }
+ // check if UTCTime encoded or GeneralizedTime
+ if (derVal.data.available() == 0)
+ throw new IOException("No data encoded for CertificateValidity");
+
+ DerInputStream derIn = new DerInputStream(derVal.toByteArray());
+ DerValue[] seq = derIn.getSequence(2);
+ if (seq.length != 2)
+ throw new IOException("Invalid encoding for CertificateValidity");
+
+ if (seq[0].tag == DerValue.tag_UtcTime) {
+ notBefore = derVal.data.getUTCTime();
+ } else if (seq[0].tag == DerValue.tag_GeneralizedTime) {
+ notBefore = derVal.data.getGeneralizedTime();
+ } else {
+ throw new IOException("Invalid encoding for CertificateValidity");
+ }
+
+ if (seq[1].tag == DerValue.tag_UtcTime) {
+ notAfter = derVal.data.getUTCTime();
+ } else if (seq[1].tag == DerValue.tag_GeneralizedTime) {
+ notAfter = derVal.data.getGeneralizedTime();
+ } else {
+ throw new IOException("Invalid encoding for CertificateValidity");
+ }
+ }
+
+ /**
+ * Default constructor for the class.
+ */
+ public CertificateValidity() {
+ }
+
+ /**
+ * The default constructor for this class for the specified interval.
+ *
+ * @param notBefore the date and time before which the certificate
+ * is not valid.
+ * @param notAfter the date and time after which the certificate is
+ * not valid.
+ */
+ public CertificateValidity(Date notBefore, Date notAfter) {
+ this.notBefore = notBefore;
+ this.notAfter = notAfter;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the CertificateValidity from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateValidity(DerInputStream in) throws IOException {
+ DerValue derVal = in.getDerValue();
+ construct(derVal);
+ }
+
+ /**
+ * Return the validity period as user readable string.
+ */
+ public String toString() {
+ if (notBefore == null || notAfter == null)
+ return "";
+ return ("Validity: [From: " + notBefore.toString() +
+ ",\n To: " + notAfter.toString() + "]");
+ }
+
+ /**
+ * Decode the CertificateValidity period from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ construct(derVal);
+ }
+
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws IOException {
+ encode(stream);
+ }
+
+ private synchronized void readObject(ObjectInputStream stream)
+ throws IOException {
+ decode(stream);
+ }
+
+ /**
+ * Encode the CertificateValidity period in DER form to the stream.
+ *
+ * @param out the OutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+
+ // in cases where default constructor is used check for
+ // null values
+ if (notBefore == null || notAfter == null) {
+ throw new IOException("CertAttrSet:CertificateValidity:" +
+ " null values to encode.\n");
+ }
+ DerOutputStream pair = new DerOutputStream();
+
+ if (notBefore.getTime() < YR_2050) {
+ pair.putUTCTime(notBefore);
+ } else
+ pair.putGeneralizedTime(notBefore);
+
+ if (notAfter.getTime() < YR_2050) {
+ pair.putUTCTime(notAfter);
+ } else {
+ pair.putGeneralizedTime(notAfter);
+ }
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.tag_Sequence, pair);
+
+ out.write(seq.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof Date)) {
+ throw new IOException("Attribute must be of type Date.");
+ }
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ notBefore = (Date) obj;
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ notAfter = (Date) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateValidity.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ return (getNotBefore());
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ return (getNotAfter());
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateValidity.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ notBefore = null;
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ notAfter = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateValidity.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NOT_BEFORE);
+ elements.addElement(NOT_AFTER);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Verify that the current time is within the validity period.
+ *
+ * @exception CertificateExpiredException if the certificate has expired.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid.
+ */
+ public void valid()
+ throws CertificateNotYetValidException, CertificateExpiredException {
+ Date now = new Date();
+ valid(now);
+ }
+
+ /**
+ * Verify that the passed time is within the validity period.
+ *
+ * @param now the Date against which to compare the validity
+ * period.
+ *
+ * @exception CertificateExpiredException if the certificate has expired
+ * with respect to the <code>Date</code> supplied.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid with respect to the <code>Date</code> supplied.
+ *
+ */
+ public void valid(Date now)
+ throws CertificateNotYetValidException, CertificateExpiredException {
+ /*
+ * we use the internal Dates rather than the passed in Date
+ * because someone could override the Date methods after()
+ * and before() to do something entirely different.
+ */
+ if (notBefore.after(now)) {
+ throw new CertificateNotYetValidException("NotBefore: " +
+ notBefore.toString());
+ }
+ if (notAfter.before(now)) {
+ throw new CertificateExpiredException("NotAfter: " +
+ notAfter.toString());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateVersion.java b/base/util/src/netscape/security/x509/CertificateVersion.java
new file mode 100644
index 000000000..d3659779f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateVersion.java
@@ -0,0 +1,247 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the version of the X509 Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.8
+ * @see CertAttrSet
+ */
+public class CertificateVersion implements CertAttrSet {
+ /**
+ * X509Certificate Version 1
+ */
+ public static final int V1 = 0;
+ /**
+ * X509Certificate Version 2
+ */
+ public static final int V2 = 1;
+ /**
+ * X509Certificate Version 3
+ */
+ public static final int V3 = 2;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.version";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "version";
+ public static final String VERSION = "number";
+
+ // Private data members
+ int version = V1;
+
+ // Returns the version number.
+ private int getVersion() {
+ return (version);
+ }
+
+ // Construct the class from the passed DerValue
+ private void construct(DerValue derVal) throws IOException {
+ if (derVal.isConstructed() && derVal.isContextSpecific()) {
+ derVal = derVal.data.getDerValue();
+ version = derVal.getInteger().toInt();
+ if (derVal.data.available() != 0) {
+ throw new IOException("X.509 version, bad format");
+ }
+ }
+ }
+
+ /**
+ * The default constructor for this class,
+ * sets the version to 0 (i.e. X.509 version 1).
+ */
+ public CertificateVersion() {
+ version = V1;
+ }
+
+ /**
+ * The constructor for this class for the required version.
+ *
+ * @param version the version for the certificate.
+ * @exception IOException if the version is not valid.
+ */
+ public CertificateVersion(int version) throws IOException {
+
+ // check that it is a valid version
+ if (version == V1 || version == V2 || version == V3)
+ this.version = version;
+ else {
+ throw new IOException("X.509 Certificate version " +
+ version + " not supported.\n");
+ }
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the CertificateVersion from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateVersion(DerInputStream in) throws IOException {
+ version = V1;
+ DerValue derVal = in.getDerValue();
+
+ construct(derVal);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the CertificateVersion from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateVersion(InputStream in) throws IOException {
+ version = V1;
+ DerValue derVal = new DerValue(in);
+
+ construct(derVal);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DerValue.
+ *
+ * @param val the Der encoded value.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateVersion(DerValue val) throws IOException {
+ version = V1;
+
+ construct(val);
+ }
+
+ /**
+ * Return the version number of the certificate.
+ */
+ public String toString() {
+ return ("Version: V" + (version + 1));
+ }
+
+ /**
+ * Encode the CertificateVersion period in DER form to the stream.
+ *
+ * @param out the OutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ // Nothing for default
+ if (version == V1) {
+ return;
+ }
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(version));
+
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
+ tmp);
+
+ out.write(seq.toByteArray());
+ }
+
+ /**
+ * Decode the CertificateVersion period in DER form from the stream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ construct(derVal);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof Integer)) {
+ throw new IOException("Attribute must be of type Integer.");
+ }
+ if (name.equalsIgnoreCase(VERSION)) {
+ version = ((Integer) obj).intValue();
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateVersion.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(VERSION)) {
+ return (Integer.valueOf(getVersion()));
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateVersion.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(VERSION)) {
+ version = V1;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateVersion.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(VERSION);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Compare versions.
+ */
+ public int compare(int vers) {
+ return (version - vers);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/CertificateX509Key.java b/base/util/src/netscape/security/x509/CertificateX509Key.java
new file mode 100644
index 000000000..c7003bb8e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/CertificateX509Key.java
@@ -0,0 +1,190 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the X509Key attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.5
+ * @see CertAttrSet
+ */
+public class CertificateX509Key implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6718749024328681131L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.key";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "key";
+ public static final String KEY = "value";
+
+ // Private data member
+ private X509Key key;
+
+ /**
+ * Default constructor for the certificate attribute.
+ *
+ * @param key the X509Key
+ */
+ public CertificateX509Key(X509Key key) {
+ this.key = key;
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the X509Key from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateX509Key(DerInputStream in) throws IOException {
+ DerValue val = in.getDerValue();
+ key = X509Key.parse(val);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the X509Key from.
+ * @exception IOException on decoding errors.
+ */
+ public CertificateX509Key(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ key = X509Key.parse(val);
+ }
+
+ /**
+ * Return the key as printable string.
+ */
+ public String toString() {
+ if (key == null)
+ return "";
+ return (key.toString());
+ }
+
+ /**
+ * Decode the key in DER form from the stream.
+ *
+ * @param in the InputStream to unmarshal the contents from
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ key = X509Key.parse(val);
+ }
+
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws IOException {
+ encode(stream);
+ }
+
+ private synchronized void readObject(ObjectInputStream stream)
+ throws IOException {
+ decode(stream);
+ }
+
+ /**
+ * Encode the key in DER form to the stream.
+ *
+ * @param out the OutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ key.encode(tmp);
+
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof X509Key)) {
+ throw new IOException("Attribute must be of type X509Key.");
+ }
+ if (name.equalsIgnoreCase(KEY)) {
+ this.key = (X509Key) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateX509Key.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY)) {
+ return (key);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateX509Key.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY)) {
+ key = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet: CertificateX509Key.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(KEY);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/DNSName.java b/base/util/src/netscape/security/x509/DNSName.java
new file mode 100644
index 000000000..831f51cc1
--- /dev/null
+++ b/base/util/src/netscape/security/x509/DNSName.java
@@ -0,0 +1,82 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the DNSName as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class DNSName implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2907649488092607056L;
+ private String name;
+
+ /**
+ * Create the DNSName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER DNSName.
+ * @exception IOException on error.
+ */
+ public DNSName(DerValue derValue) throws IOException {
+ name = derValue.getIA5String();
+ }
+
+ /**
+ * Create the DNSName object with the specified name.
+ *
+ * @param name the DNSName.
+ */
+ public DNSName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_DNS);
+ }
+
+ /**
+ * Encode the DNS name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the DNSName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putIA5String(name);
+ }
+
+ /**
+ * Convert the name into user readable string.
+ */
+ public String toString() {
+ return ("DNSName: " + name);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/DeltaCRLIndicatorExtension.java b/base/util/src/netscape/security/x509/DeltaCRLIndicatorExtension.java
new file mode 100755
index 000000000..da870f4fd
--- /dev/null
+++ b/base/util/src/netscape/security/x509/DeltaCRLIndicatorExtension.java
@@ -0,0 +1,239 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.math.BigInteger;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Delta CRL Indicator Extension.
+ *
+ * <p>
+ * The delta CRL indicator is a critical CRL extension that identifies a delta-CRL. The value of BaseCRLNumber
+ * identifies the CRL number of the base CRL that was used as the starting point in the generation of this delta- CRL.
+ * The delta-CRL contains the changes between the base CRL and the current CRL issued along with the delta-CRL.
+ *
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class DeltaCRLIndicatorExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7182919216525364676L;
+ /**
+ * Attribute name.
+ */
+ public static final String NAME = "DeltaCRLIndicator";
+ public static final String NUMBER = "value";
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.27";
+
+ private BigInt baseCRLNumber = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(DeltaCRLIndicatorExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ if (baseCRLNumber == null)
+ throw new IOException("Unintialized delta CRL indicator extension");
+ DerOutputStream os = new DerOutputStream();
+ os.putInteger(this.baseCRLNumber);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a DeltaCRLIndicatorExtension with the integer value.
+ * The criticality is set to true.
+ *
+ * @param baseCRLNum the value to be set for the extension.
+ */
+ public DeltaCRLIndicatorExtension(int baseCRLNum) throws IOException {
+ this.baseCRLNumber = new BigInt(baseCRLNum);
+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create a DeltaCRLIndicatorExtension with the BigInteger value.
+ * The criticality is set to true.
+ *
+ * @param baseCRLNum the value to be set for the extension.
+ */
+ public DeltaCRLIndicatorExtension(BigInteger baseCRLNum) throws IOException {
+ this.baseCRLNumber = new BigInt(baseCRLNum);
+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create a DeltaCRLIndicatorExtension with the BigInteger value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param baseCRLNum the value to be set for the extension.
+ */
+ public DeltaCRLIndicatorExtension(Boolean critical, BigInteger baseCRLNum)
+ throws IOException {
+ this.baseCRLNumber = new BigInt(baseCRLNum);
+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public DeltaCRLIndicatorExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ this.baseCRLNumber = val.getInteger();
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ if (!(obj instanceof BigInteger)) {
+ throw new IOException("Attribute must be of type BigInteger.");
+ }
+ baseCRLNumber = new BigInt((BigInteger) obj);
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:DeltaCRLIndicator.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ if (baseCRLNumber == null)
+ return null;
+ else
+ return baseCRLNumber.toBigInteger();
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:DeltaCRLIndicator.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(NUMBER)) {
+ baseCRLNumber = null;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:DeltaCRLIndicator.");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the DeltaCRLIndicatorExtension.
+ */
+ public String toString() {
+ String s = super.toString() + "Delta CRL Indicator: " +
+ ((baseCRLNumber == null) ? "" : baseCRLNumber.toString())
+ + "\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id;
+ this.critical = true;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NUMBER);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/DirStrConverter.java b/base/util/src/netscape/security/x509/DirStrConverter.java
new file mode 100644
index 000000000..776344c0a
--- /dev/null
+++ b/base/util/src/netscape/security/x509/DirStrConverter.java
@@ -0,0 +1,171 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+
+import netscape.security.util.ASN1CharStrConvMap;
+import netscape.security.util.DerValue;
+
+/**
+ * A DirStrConverter converts a string to a DerValue of ASN.1 Directory String,
+ * which is a CHOICE of Printable (subset of ASCII), T.61 (Teletex) or
+ * Universal String (UCS-4), and vice versa.
+ *
+ * <p>
+ * The string to DerValue conversion is done as follows. If the string has only PrintableString characters it is
+ * converted to a ASN.1 Printable String using the PrintableString encoder from the global default ASN1CharStrConvMap.
+ * If it has only characters covered in the PrintableString or T.61 character set it is converted to a ASN.1 T.61 string
+ * using the T.61 encoder from the ASN1CharStrCovnMap. Otherwise it is converted to a ASN.1 UniversalString (UCS-4
+ * character set) which covers all characters.
+ *
+ * @see AVAValueConverter
+ * @see ASN1CharStrConvMap
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public class DirStrConverter implements AVAValueConverter {
+ // public constructors
+
+ /**
+ * Constructs a DirStrConverter.
+ */
+ public DirStrConverter() {
+ }
+
+ // public functions
+
+ /**
+ * Converts a string to a DER encoded ASN1 Directory String, which is a
+ * CHOICE of PrintableString, T.61String or UniversalString.
+ * The string is taken as is i.e. should not be in Ldap DN string syntax.
+ *
+ * @param ds a string representing a directory string value.
+ *
+ * @return a DerValue
+ *
+ * @exception IOException if the string cannot be converted, such as
+ * when a UniversalString encoder
+ * isn't available and the string contains
+ * characters covered only in the universal
+ * string (or UCS-4) character set.
+ */
+ private static byte[] DefEncodingOrder =
+ new byte[] {
+ DerValue.tag_PrintableString,
+ DerValue.tag_T61String,
+ DerValue.tag_UniversalString
+ };
+
+ public static synchronized void
+ setDefEncodingOrder(byte[] defEncodingOrder) {
+ DefEncodingOrder = defEncodingOrder;
+ }
+
+ public DerValue getValue(String ds)
+ throws IOException {
+ return getValue(ds, DefEncodingOrder);
+ }
+
+ /**
+ * Like getValue(String) with specified DER tags as encoding order.
+ */
+ public DerValue getValue(String valueString, byte[] tags) throws IOException {
+ // try to convert to printable, then t61 the universal -
+ // i.e. from minimal to the most liberal.
+
+ if (tags == null || tags.length == 0)
+ tags = DefEncodingOrder;
+
+ for (int i = 0; i < tags.length; i++) {
+ try {
+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tags[i]);
+ if (encoder == null)
+ continue;
+
+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray());
+ ByteBuffer byteBuffer = encoder.encode(charBuffer);
+
+ return new DerValue(tags[i], byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit());
+
+ } catch (CharacterCodingException e) {
+ continue;
+ }
+ }
+
+ throw new IOException(
+ "Cannot convert the directory string value to a ASN.1 type");
+ }
+
+ /**
+ * Creates a DerValue from a BER encoded value, obtained from for example
+ * a attribute value in octothorpe form of a Ldap DN string.
+ * Checks if the BER encoded value is legal for a DirectoryString.
+ *
+ * NOTE: currently only supports DER encoding for the BER encoded value.
+ *
+ * @param berStream Byte array of a BER encoded value.
+ *
+ * @return DerValue object.
+ *
+ * @exception IOException If the BER value cannot be converted to a
+ * valid Directory String DER value.
+ */
+ public DerValue getValue(byte[] berByteStream)
+ throws IOException {
+ DerValue value = new DerValue(berByteStream);
+
+ /*
+ if (value.tag != DerValue.tag_PrintableString &&
+ value.tag != DerValue.tag_T61String &&
+ value.tag != DerValue.tag_UniversalString)
+ throw new IOException("Invalid Directory String AVA Value");
+ */
+
+ return value;
+ }
+
+ /**
+ * Converts a DerValue to a string.
+ * The string is not in any syntax, such as RFC1779 string syntax.
+ *
+ * @param avaValue a DerValue
+ * @return a string if the value can be converted.
+ * @exception IOException if a decoder needed for the
+ * conversion is not available.
+ */
+ public String getAsString(DerValue avaValue)
+ throws IOException {
+ /*
+ if (avaValue.tag != DerValue.tag_PrintableString &&
+ avaValue.tag != DerValue.tag_BMPString &&
+ avaValue.tag != DerValue.tag_UniversalString &&
+ avaValue.tag != DerValue.tag_T61String)
+ throw new IllegalArgumentException(
+ "Invalid Directory String value");
+ // NOTE will return null if a decoder is not available.
+ */
+ return avaValue.getASN1CharString();
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/DisplayText.java b/base/util/src/netscape/security/x509/DisplayText.java
new file mode 100644
index 000000000..a379617a7
--- /dev/null
+++ b/base/util/src/netscape/security/x509/DisplayText.java
@@ -0,0 +1,82 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the DisplayText.
+ *
+ * DisplayText ::= CHOICE {
+ * visibleString VisibleString (SIZE (1..200)),
+ * bmpString BMPString (SIZE (1..200)),
+ * utf8String UTF8String (SIZE (1..200)),
+ * }
+ *
+ * @author Thomas Kwan
+ */
+public class DisplayText {
+
+ /** Tag value indicating an ASN.1 "BMPString" value. */
+ public final static byte tag_IA5String = 0x16;
+ public final static byte tag_BMPString = 0x1E;
+ public final static byte tag_VisibleString = 0x1A;
+ public final static byte tag_UTF8String = 0x0C;
+
+ private byte mTag;
+ private String mS = null;
+
+ public DisplayText(byte tag, String s) {
+ mTag = tag;
+ mS = s;
+ }
+
+ public DisplayText(DerValue val) throws IOException {
+ mTag = val.tag;
+ mS = val.getAsString();
+ }
+
+ /**
+ * Write the DisplayText to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putStringType(mTag, mS);
+ }
+
+ public String getText() {
+ return mS;
+ }
+
+ public String toString() {
+ if (mTag == tag_IA5String) {
+ return "IA5String: " + mS;
+ } else if (mTag == tag_BMPString) {
+ return "BMPString: " + mS;
+ } else if (mTag == tag_VisibleString) {
+ return "VisibleString: " + mS;
+ } else {
+ return "UTF8String: " + mS;
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/EDIPartyName.java b/base/util/src/netscape/security/x509/EDIPartyName.java
new file mode 100644
index 000000000..0c69242cc
--- /dev/null
+++ b/base/util/src/netscape/security/x509/EDIPartyName.java
@@ -0,0 +1,154 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the EDIPartyName of the GeneralName choice.
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ * </pre>
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.2
+ * @see GeneralName
+ * @see GeneralNames
+ * @see GeneralNameInterface
+ */
+public class EDIPartyName implements GeneralNameInterface {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8669257424766789063L;
+ // Private data members
+ private static final byte TAG_ASSIGNER = 0;
+ private static final byte TAG_PARTYNAME = 1;
+
+ private String assigner = null;
+ private String party = null;
+
+ /**
+ * Create the EDIPartyName object from the specified names.
+ *
+ * @param assignerName the name of the assigner
+ * @param partyName the name of the EDI party.
+ */
+ public EDIPartyName(String assignerName, String partyName) {
+ this.assigner = assignerName;
+ this.party = partyName;
+ }
+
+ /**
+ * Create the EDIPartyName object from the specified name.
+ *
+ * @param partyName the name of the EDI party.
+ */
+ public EDIPartyName(String partyName) {
+ this.party = partyName;
+ }
+
+ /**
+ * Create the EDIPartyName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER EDIPartyName.
+ * @exception IOException on error.
+ */
+ public EDIPartyName(DerValue derValue) throws IOException {
+ DerInputStream in = new DerInputStream(derValue.toByteArray());
+ DerValue[] seq = in.getSequence(2);
+
+ int len = seq.length;
+ if (len < 1 || len > 2)
+ throw new IOException("Invalid encoding of EDIPartyName");
+
+ for (int i = 0; i < len; i++) {
+ DerValue opt = seq[i];
+ if (opt.isContextSpecific((byte) TAG_ASSIGNER) &&
+ !opt.isConstructed()) {
+ if (assigner != null)
+ throw new IOException("Duplicate nameAssigner found in"
+ + " EDIPartyName");
+ opt = opt.data.getDerValue();
+ assigner = opt.getAsString();
+ }
+ if (opt.isContextSpecific((byte) TAG_PARTYNAME) &&
+ !opt.isConstructed()) {
+ if (party != null)
+ throw new IOException("Duplicate partyName found in"
+ + " EDIPartyName");
+ opt = opt.data.getDerValue();
+ party = opt.getAsString();
+ }
+ }
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_EDI);
+ }
+
+ /**
+ * Encode the EDI party name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the EDIPartyName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tagged = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (assigner != null) {
+ DerOutputStream tmp2 = new DerOutputStream();
+ // XXX - shd check is chars fit into PrintableString
+ tmp2.putPrintableString(assigner);
+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_ASSIGNER), tmp2);
+ }
+ if (party == null)
+ throw new IOException("Cannot have null partyName");
+
+ // XXX - shd check is chars fit into PrintableString
+ tmp.putPrintableString(party);
+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_PARTYNAME), tmp);
+
+ out.write(DerValue.tag_Sequence, tagged);
+ }
+
+ /**
+ * Return the printable string.
+ */
+ public String toString() {
+ return ("EDIPartyName: " +
+ ((assigner == null) ? "" :
+ (" nameAssigner = " + assigner + ","))
+ + " partyName = " + party);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/Extension.java b/base/util/src/netscape/security/x509/Extension.java
new file mode 100644
index 000000000..7dc9e2890
--- /dev/null
+++ b/base/util/src/netscape/security/x509/Extension.java
@@ -0,0 +1,199 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Represent a X509 Extension Attribute.
+ *
+ * <p>
+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a
+ * "Driving License Certificate" could have the driving license number as a extension.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ *
+ * <pre>
+ * ASN.1 definition of Extension:
+ * Extension ::= SEQUENCE {
+ * ExtensionId OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extensionValue OCTET STRING
+ * }
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ */
+public class Extension implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -643549610716024753L;
+ protected ObjectIdentifier extensionId = null;
+ protected boolean critical = false;
+ protected byte[] extensionValue = null;
+
+ /**
+ * Default constructor. Used only by sub-classes.
+ */
+ public Extension() {
+ }
+
+ /**
+ * Constructs an extension from a DER encoded array of bytes.
+ */
+ public Extension(DerValue derVal) throws IOException {
+
+ DerInputStream in = derVal.toDerInputStream();
+
+ // Object identifier
+ extensionId = in.getOID();
+
+ // If the criticality flag was false, it will not have been encoded.
+ DerValue val = in.getDerValue();
+ if (val.tag == DerValue.tag_Boolean) {
+ critical = val.getBoolean();
+
+ // Extension value (DER encoded)
+ val = in.getDerValue();
+ extensionValue = val.getOctetString();
+ } else {
+ critical = false;
+ extensionValue = val.getOctetString();
+ }
+ }
+
+ /**
+ * Constructs an Extension from individual components of ObjectIdentifier,
+ * criticality and the DER encoded OctetString.
+ *
+ * @param extensionId the ObjectIdentifier of the extension
+ * @param critical the boolean indicating if the extension is critical
+ * @param extensionValue the DER encoded octet string of the value.
+ */
+ public Extension(ObjectIdentifier extensionId, boolean critical,
+ byte[] extensionValue) throws IOException {
+ this.extensionId = extensionId;
+ this.critical = critical;
+ // passed in a DER encoded octet string, strip off the tag
+ // and length
+ DerValue inDerVal = new DerValue(extensionValue);
+ this.extensionValue = inDerVal.getOctetString();
+ }
+
+ /**
+ * Constructs an Extension from another extension. To be used for
+ * creating decoded subclasses.
+ *
+ * @param ext the extension to create from.
+ */
+ public Extension(Extension ext) {
+ this.extensionId = ext.extensionId;
+ this.critical = ext.critical;
+ this.extensionValue = ext.extensionValue;
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream bytes = new DerOutputStream();
+
+ if (extensionId == null)
+ throw new IOException("Null OID to encode for the extension!");
+
+ bytes.putOID(extensionId);
+ if (critical)
+ bytes.putBoolean(critical);
+ if (extensionValue != null)
+ bytes.putOctetString(extensionValue);
+
+ out.write(DerValue.tag_Sequence, bytes);
+ }
+
+ /**
+ * Returns true if extension is critical.
+ */
+ public boolean isCritical() {
+ return (critical);
+ }
+
+ public void setCritical(boolean c) {
+ critical = c;
+ }
+
+ public void clearValue() {
+ extensionValue = null;
+ }
+
+ /**
+ * Returns the ObjectIdentifier of the extension.
+ */
+ public ObjectIdentifier getExtensionId() {
+ return (extensionId);
+ }
+
+ public void setExtensionId(ObjectIdentifier oid) {
+ extensionId = oid;
+ }
+
+ /**
+ * Returns the extension value as an byte array for further processing.
+ * Note, this is the raw DER value of the extension, not the DER
+ * encoded octet string which is in the certificate.
+ */
+ public byte[] getExtensionValue() {
+ if (extensionValue == null)
+ return null;
+
+ byte[] dup = new byte[extensionValue.length];
+ System.arraycopy(extensionValue, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ public void setExtensionValue(byte value[]) {
+ extensionValue = value;
+ }
+
+ /**
+ * Returns the Extension in user readable form.
+ */
+ public String toString() {
+ String s = "ObjectId: " + extensionId.toString();
+ if (critical) {
+ s += " Criticality=true\n";
+ } else {
+ s += " Criticality=false\n";
+ }
+ return (s);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/Extensions.java b/base/util/src/netscape/security/x509/Extensions.java
new file mode 100644
index 000000000..622367ab6
--- /dev/null
+++ b/base/util/src/netscape/security/x509/Extensions.java
@@ -0,0 +1,226 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the Extensions attribute for the Certificate.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.11
+ * @see CertAttrSet
+ */
+public class Extensions extends Vector<Extension>
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4597917347772057433L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions";
+ /**
+ * name
+ */
+ public static final String NAME = "extensions";
+
+ private Hashtable<String, Extension> map;
+
+ // Parse the encoded extension
+ public void parseExtension(Extension ext) throws IOException {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<CertAttrSet> extClass = (Class<CertAttrSet>) OIDMap.getClass(ext.getExtensionId());
+ if (extClass == null) { // Unsupported extension
+ if (ext.isCritical()) {
+ throw new IOException("Unsupported CRITICAL extension: "
+ + ext.getExtensionId());
+ } else {
+ map.put(ext.getExtensionId().toString(), ext);
+ addElement(ext);
+ return;
+ }
+ }
+ Class<?>[] params = { Boolean.class, Object.class };
+ Constructor<CertAttrSet> cons = extClass.getConstructor(params);
+
+ byte[] extData = ext.getExtensionValue();
+ int extLen = extData.length;
+ Object value = Array.newInstance(byte.class, extLen);
+
+ for (int i = 0; i < extLen; i++) {
+ Array.setByte(value, i, extData[i]);
+ }
+ Object[] passed = new Object[] { new Boolean(ext.isCritical()),
+ value };
+ CertAttrSet certExt = cons.newInstance(passed);
+ map.put(certExt.getName(), (Extension) certExt);
+ addElement((Extension) certExt);
+
+ } catch (NoSuchMethodException nosuch) {
+ throw new IOException(nosuch.toString());
+ } catch (InvocationTargetException invk) {
+ throw new IOException(invk.getTargetException().toString());
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+
+ /**
+ * Default constructor for the certificate attribute.
+ */
+ public Extensions() {
+ map = new Hashtable<String, Extension>();
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the Extension from.
+ * @exception IOException on decoding errors.
+ */
+ public Extensions(DerInputStream in)
+ throws IOException {
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = in.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ }
+
+ /**
+ * Decode the extensions from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ DerInputStream str = val.toDerInputStream();
+
+ map = new Hashtable<String, Extension>();
+ DerValue[] exts = str.getSequence(5);
+
+ for (int i = 0; i < exts.length; i++) {
+ Extension ext = new Extension(exts[i]);
+ parseExtension(ext);
+ }
+ }
+
+ /**
+ * Encode the extensions in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception CertificateException on encoding errors.
+ * @exception IOException on errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ DerOutputStream extOut = new DerOutputStream();
+ for (int i = 0; i < size(); i++) {
+ Object thisOne = elementAt(i);
+ if (thisOne instanceof CertAttrSet)
+ ((CertAttrSet) thisOne).encode(extOut);
+ else if (thisOne instanceof Extension)
+ ((Extension) thisOne).encode(extOut);
+ else
+ throw new CertificateException("Invalid extension object");
+ }
+
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.tag_Sequence, extOut);
+
+ out.write(seq.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ *
+ * @param name the extension name used in the cache.
+ * @param obj the object to set.
+ * @exception IOException if the object could not be cached.
+ */
+ public void set(String name, Object obj) throws IOException {
+ map.put(name, (Extension) obj);
+ addElement((Extension) obj);
+ }
+
+ /**
+ * Get the attribute value.
+ *
+ * @param name the extension name used in the lookup.
+ * @exception IOException if named extension is not found.
+ */
+ public Object get(String name) throws IOException {
+ Object obj = map.get(name);
+ if (obj == null) {
+ throw new IOException("No extension found with name " + name);
+ }
+ return (obj);
+ }
+
+ /**
+ * Delete the attribute value.
+ *
+ * @param name the extension name used in the lookup.
+ * @exception IOException if named extension is not found.
+ */
+ public void delete(String name) throws IOException {
+ Object obj = map.get(name);
+ if (obj == null) {
+ throw new IOException("No extension found with name " + name);
+ }
+ map.remove(name);
+ removeElement(obj);
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ return map.keys();
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/FreshestCRLExtension.java b/base/util/src/netscape/security/x509/FreshestCRLExtension.java
new file mode 100644
index 000000000..c749ae04e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/FreshestCRLExtension.java
@@ -0,0 +1,396 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+
+/**
+ * An extension that tells applications where to find
+ * the latest (freshest) delta CRL for this certificate
+ * or full CRL.
+ *
+ * <pre>
+ * cRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL }
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6) }
+ * </pre>
+ */
+public class FreshestCRLExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8040203589629281781L;
+
+ // vector of CRLDistributionPoint
+ private SEQUENCE distributionPoints = new SEQUENCE();
+
+ public FreshestCRLExtension() {
+ this.extensionId = PKIXExtensions.FreshestCRL_Id;
+ this.critical = false;
+ }
+
+ // Cached DER-encoding to improve performance.
+ private byte[] cachedEncoding = null;
+
+ // Attribute name
+ public static final String NAME = "FreshestCRL";
+
+ // The Object Identifier for this extension.
+ public static final String OID = "2.5.29.46";
+
+ static {
+ try {
+ OIDMap.addAttribute(FreshestCRLExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ /**
+ * This constructor is called by the CertificateExtensions class to decode
+ * an extension whose OID indicates it is a CRLDistributionsPoints
+ * extension.
+ */
+ public FreshestCRLExtension(Boolean critical, Object value)
+ //throws IOException
+ {
+ try {
+ this.extensionId = PKIXExtensions.FreshestCRL_Id;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+
+ // decode the value
+ try {
+ SEQUENCE.OF_Template seqOfCRLDP =
+ new SEQUENCE.OF_Template(CRLDistributionPoint.getTemplate());
+
+ distributionPoints =
+ (SEQUENCE) ASN1Util.decode(seqOfCRLDP, extensionValue);
+ } catch (InvalidBERException e) {
+ throw new IOException("Invalid BER-encoding: " + e.toString());
+ }
+ } catch (IOException e) {
+ System.out.println("Big error");
+ System.out.println(e);
+ e.printStackTrace();
+ //throw e;
+ }
+ }
+
+ /**
+ * Creates a new FreshestCRL extension, with the given
+ * distribution point as the first element.
+ */
+ public FreshestCRLExtension(CRLDistributionPoint dp) {
+ this.extensionId = PKIXExtensions.FreshestCRL_Id;
+ this.critical = false;
+ distributionPoints.addElement(dp);
+ }
+
+ /**
+ * Adds an additional distribution point to the end of the sequence.
+ */
+ public void addPoint(CRLDistributionPoint dp) {
+ distributionPoints.addElement(dp);
+ cachedEncoding = null;
+ }
+
+ /**
+ * Returns the number of distribution points in the sequence.
+ */
+ public int getNumPoints() {
+ return distributionPoints.size();
+ }
+
+ /**
+ * Returns the DistributionPoint at the given index in the sequence.
+ */
+ public CRLDistributionPoint getPointAt(int index) {
+ return (CRLDistributionPoint) distributionPoints.elementAt(index);
+ }
+
+ /**
+ * Sets the criticality of this extension. PKIX dictates that this
+ * extension SHOULD NOT be critical, so applications can make it critical
+ * if they have a very good reason. By default, the extension is not
+ * critical.
+ */
+ public void setCritical(boolean critical) {
+ this.critical = critical;
+ }
+
+ /**
+ * Encodes this extension to the given DerOutputStream.
+ * This method re-encodes each time it is called, so it is not very
+ * efficient.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ extensionValue = ASN1Util.encode(distributionPoints);
+ super.encode(out);
+ }
+
+ /**
+ * Should be called if any change is made to this data structure
+ * so that the cached DER encoding can be discarded.
+ */
+ public void flushCachedEncoding() {
+ cachedEncoding = null;
+ }
+
+ /////////////////////////////////////////////////////////////
+ // CertAttrSet interface
+ // This interface is not really appropriate for this extension
+ // because it is so complicated. Therefore, we only provide a
+ // minimal implementation.
+ /////////////////////////////////////////////////////////////
+ public String toString() {
+ return NAME;
+ }
+
+ /**
+ * DER-encodes this extension to the given OutputStream.
+ */
+ public void encode(OutputStream ostream)
+ throws CertificateException, IOException {
+ if (cachedEncoding == null) {
+ // only re-encode if necessary
+ DerOutputStream tmp = new DerOutputStream();
+ encode(tmp);
+ cachedEncoding = tmp.toByteArray();
+ }
+ ostream.write(cachedEncoding);
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ throw new IOException("Not supported");
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:FreshestCRLExtension");
+ }
+
+ public Object get(String name)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:FreshestCRLExtension");
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:FreshestCRLExtension");
+ }
+
+ /*
+ * TODO replacewith empty collection
+ */
+ public Enumeration<String> getAttributeNames() {
+ return (new Vector<String>()).elements();
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Test driver.
+ */
+ public static void main(String args[]) {
+
+ try {
+
+ if (args.length != 1) {
+ System.out.println("Usage: FreshestCRLExtentions " +
+ "<outfile>");
+ System.exit(-1);
+ }
+
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(args[0]));
+
+ // URI only
+ CRLDistributionPoint cdp = new CRLDistributionPoint();
+ URIName uri = new URIName("http://www.mycrl.com/go/here");
+ GeneralNames generalNames = new GeneralNames();
+ generalNames.addElement(uri);
+ cdp.setFullName(generalNames);
+ FreshestCRLExtension crldpExt =
+ new FreshestCRLExtension(cdp);
+
+ // DN only
+ cdp = new CRLDistributionPoint();
+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" +
+ ",OU=Certificate Server,O=Fedora,C=US");
+ generalNames = new GeneralNames();
+ generalNames.addElement(dn);
+ cdp.setFullName(generalNames);
+ crldpExt.addPoint(cdp);
+
+ // DN + reason
+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 });
+ cdp = new CRLDistributionPoint();
+ cdp.setFullName(generalNames);
+ cdp.setReasons(ba);
+ crldpExt.addPoint(cdp);
+
+ // relative DN + reason + crlIssuer
+ cdp = new CRLDistributionPoint();
+ RDN rdn = new RDN("OU=foobar dept");
+ cdp.setRelativeName(rdn);
+ cdp.setReasons(ba);
+ cdp.setCRLIssuer(generalNames);
+ crldpExt.addPoint(cdp);
+
+ crldpExt.setCritical(true);
+ crldpExt.encode(bos);
+
+ bos.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Represents a reason that a cert may be revoked. These reasons are
+ * expressed in a ReasonFlags bit string.
+ */
+ public static class Reason {
+
+ private String name;
+ private byte bitMask;
+
+ private Reason() {
+ }
+
+ private Reason(String name, byte bitMask) {
+ this.name = name;
+ this.bitMask = bitMask;
+ map.put(name, this);
+ list.addElement(this);
+ }
+
+ private static Hashtable<String, Reason> map = new Hashtable<String, Reason>();
+ private static Vector<Reason> list = new Vector<Reason>();
+
+ public static Reason fromString(String name) {
+ return map.get(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public byte getBitMask() {
+ return bitMask;
+ }
+
+ /**
+ * Given a bit array representing reason flags, extracts the reasons
+ * and returns them as an array.
+ *
+ * @param bitFlags A bit vector containing reason flags.
+ * @return An array of reasons contained in the bit vector.
+ * May be zero-length but will not be null.
+ */
+ public static Reason[] bitArrayToReasonArray(byte bitFlags) {
+ return bitArrayToReasonArray(new byte[] { bitFlags });
+ }
+
+ /**
+ * Given a bit array representing reason flags, extracts the reasons
+ * and returns them as an array. Currently, only the first byte
+ * of the bitflags are examined.
+ *
+ * @param bitFlags A bit vector containing reason flags. The format
+ * is big-endian (MSB first). Only the first byte is examined.
+ * @return An array of reasons contained in the bit vector.
+ * May be zero-length but will not be null.
+ */
+ public static Reason[] bitArrayToReasonArray(byte[] bitFlags) {
+ byte first = bitFlags[0];
+ int size = list.size();
+ Vector<Reason> result = new Vector<Reason>();
+ for (int i = 0; i < size; i++) {
+ Reason r = (Reason) list.elementAt(i);
+ byte b = r.getBitMask();
+ if ((first & b) != 0) {
+ result.addElement(r);
+ }
+ }
+ size = result.size();
+ Reason[] retval = new Reason[size];
+ for (int i = 0; i < size; i++) {
+ retval[i] = result.elementAt(i);
+ }
+ return retval;
+ }
+
+ public static final Reason UNUSED =
+ new Reason("unused", (byte) 0x80);
+ public static final Reason KEY_COMPROMISE =
+ new Reason("keyCompromise", (byte) 0x40);
+ public static final Reason CA_COMPROMISE =
+ new Reason("cACompromise", (byte) 0x20);
+ public static final Reason AFFILIATION_CHANGED =
+ new Reason("affiliationChanged", (byte) 0x10);
+ public static final Reason SUPERSEDED =
+ new Reason("superseded", (byte) 0x08);
+ public static final Reason CESSATION_OF_OPERATION =
+ new Reason("cessationOfOperation", (byte) 0x04);
+ public static final Reason CERTIFICATE_HOLD =
+ new Reason("certificateHold", (byte) 0x02);
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/GeneralName.java b/base/util/src/netscape/security/x509/GeneralName.java
new file mode 100644
index 000000000..5ed98d830
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralName.java
@@ -0,0 +1,199 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the ASN.1 GeneralName object class.
+ * <p>
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER
+ * }
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ */
+public class GeneralName implements GeneralNameInterface {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2244101501095555042L;
+ // Private data members
+ private GeneralNameInterface name = null;
+
+ /**
+ * Default constructor for the class.
+ *
+ * @param name the selected CHOICE from the list.
+ */
+ public GeneralName(GeneralNameInterface name) {
+ this.name = name;
+ }
+
+ /**
+ * Create the object from its DER encoded value.
+ *
+ * @param encName the DER encoded GeneralName.
+ */
+ public GeneralName(DerValue encName) throws IOException {
+ short tag = (byte) (encName.tag & 0x1f);
+
+ // NB. this is always encoded with the IMPLICIT tag
+ // The checks only make sense if we assume implicit tagging,
+ // with explicit tagging the form is always constructed.
+ switch (tag) {
+ case GeneralNameInterface.NAME_RFC822:
+ if (encName.isContextSpecific() && !encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_IA5String);
+ name = new RFC822Name(encName);
+ } else
+ throw new IOException("Invalid encoding of RFC822 name");
+ break;
+
+ case GeneralNameInterface.NAME_DNS:
+ if (encName.isContextSpecific() && !encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_IA5String);
+ name = new DNSName(encName);
+ } else
+ throw new IOException("Invalid encoding of DNS name");
+ break;
+
+ case GeneralNameInterface.NAME_URI:
+ if (encName.isContextSpecific() && !encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_IA5String);
+ name = new URIName(encName);
+ } else
+ throw new IOException("Invalid encoding of URI");
+ break;
+
+ case GeneralNameInterface.NAME_IP:
+ if (encName.isContextSpecific() && !encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_OctetString);
+ name = new IPAddressName(encName);
+ } else
+ throw new IOException("Invalid encoding of IP address");
+ break;
+
+ case GeneralNameInterface.NAME_ANY:
+ if (encName.isContextSpecific() && encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_OctetString);
+ name = new OtherName(encName);
+ } else
+ throw new IOException("Invalid encoding of other name");
+ break;
+
+ case GeneralNameInterface.NAME_OID:
+ if (encName.isContextSpecific() && !encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_ObjectId);
+ name = new OIDName(encName);
+ } else
+ throw new IOException("Invalid encoding of OID name");
+ break;
+
+ case GeneralNameInterface.NAME_DIRECTORY:
+ if (encName.isContextSpecific() && encName.isConstructed()) {
+ // Unlike the other cases, DirectoryName is EXPLICITly
+ // tagged, because the X.500 Name type is a CHOICE.
+ // Therefore, the sequence is actually nested in the
+ // content of this value. We'll pretend it's an octet
+ // string so we can get at the content bytes.
+ encName.resetTag(DerValue.tag_OctetString);
+ byte[] content = encName.getOctetString();
+ name = new X500Name(content);
+ } else
+ throw new IOException("Invalid encoding of Directory name");
+ break;
+
+ case GeneralNameInterface.NAME_EDI:
+ if (encName.isContextSpecific() && encName.isConstructed()) {
+ encName.resetTag(DerValue.tag_Sequence);
+ name = new EDIPartyName(encName);
+ } else
+ throw new IOException("Invalid encoding of EDI name");
+ break;
+
+ default:
+ throw new IOException("Unrecognized GeneralName tag, ("
+ + tag + ")");
+ }
+ }
+
+ /**
+ * Return the type of the general name.
+ */
+ public int getType() {
+ return (name.getType());
+ }
+
+ /**
+ * Return the name as user readable string
+ */
+ public String toString() {
+ return (name.toString());
+ }
+
+ /**
+ * Encode the name to the specified DerOutputStream.
+ *
+ * @param out the DerOutputStream to encode the the GeneralName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ name.encode(tmp);
+ int nameType = name.getType();
+ boolean constructedForm;
+
+ if (nameType == GeneralNameInterface.NAME_ANY ||
+ nameType == GeneralNameInterface.NAME_X400 ||
+ nameType == GeneralNameInterface.NAME_DIRECTORY ||
+ nameType == GeneralNameInterface.NAME_EDI) {
+ constructedForm = true;
+ } else {
+ constructedForm = false;
+ }
+
+ if (nameType == GeneralNameInterface.NAME_DIRECTORY) {
+ // EXPLICIT tag, because Name is a CHOICE type
+ out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ constructedForm, (byte) nameType), tmp);
+ } else {
+ // IMPLICIT tag, the default
+ out.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ constructedForm, (byte) nameType), tmp);
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/GeneralNameInterface.java b/base/util/src/netscape/security/x509/GeneralNameInterface.java
new file mode 100644
index 000000000..4a9673663
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralNameInterface.java
@@ -0,0 +1,60 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+
+/**
+ * This interface specifies the abstract methods which have to be
+ * implemented by all the members of the GeneralNames ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ */
+public interface GeneralNameInterface extends java.io.Serializable {
+ /**
+ * The list of names supported.
+ */
+ public static final int NAME_ANY = 0;
+ public static final int NAME_RFC822 = 1;
+ public static final int NAME_DNS = 2;
+ public static final int NAME_X400 = 3;
+ public static final int NAME_DIRECTORY = 4;
+ public static final int NAME_EDI = 5;
+ public static final int NAME_URI = 6;
+ public static final int NAME_IP = 7;
+ public static final int NAME_OID = 8;
+
+ /**
+ * Return the type of the general name, as
+ * defined above.
+ */
+ int getType();
+
+ /**
+ * Encode the name to the specified DerOutputStream.
+ *
+ * @param out the DerOutputStream to encode the GeneralName to.
+ * @exception IOException thrown if the GeneralName could not be
+ * encoded.
+ */
+ void encode(DerOutputStream out) throws IOException;
+}
diff --git a/base/util/src/netscape/security/x509/GeneralNames.java b/base/util/src/netscape/security/x509/GeneralNames.java
new file mode 100644
index 000000000..9e06db5ac
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralNames.java
@@ -0,0 +1,150 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This object class represents the GeneralNames type required in
+ * X509 certificates.
+ * <p>
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ */
+public class GeneralNames extends Vector<GeneralNameInterface> {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3204492869396713312L;
+
+ /**
+ * Create the GeneralNames, decoding from the passed DerValue.
+ *
+ * <b>Caution when using this constructor. It may be broken!
+ * Better to call addElement(gni) directly where gni is
+ * a GeneralNameInterface object </b>
+ *
+ * @param derVal the DerValue to construct the GeneralNames from.
+ * @exception GeneralNamesException on decoding error.
+ * @exception IOException on error.
+ */
+ public GeneralNames(DerValue derVal)
+ throws IOException, GeneralNamesException {
+ if (derVal.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for GeneralNames.");
+ }
+ if (derVal.data.available() == 0) {
+ throw new GeneralNamesException("No data available in "
+ + "passed DER encoded value.");
+ }
+ // Decode all the GeneralName's
+ while (derVal.data.available() != 0) {
+ DerValue encName = derVal.data.getDerValue();
+
+ GeneralName name = new GeneralName(encName);
+ addElement(name);
+ }
+ }
+
+ /**
+ * Create the GeneralNames
+ *
+ * @param names a non-empty array of names to put into the
+ * generalNames
+ */
+
+ public GeneralNames(GeneralNameInterface[] names)
+ throws GeneralNamesException {
+ if (names == null || names.length == 0)
+ throw new GeneralNamesException("Cannot create empty GeneralNames");
+
+ for (int i = 0; i < names.length; i++) {
+ addElement(names[i]);
+ }
+ }
+
+ /**
+ * The default constructor for this class.
+ */
+ public GeneralNames() {
+ super(1, 1);
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception GeneralNamesException on encoding error.
+ * @exception IOException on error.
+ */
+ public void encode(DerOutputStream out)
+ throws IOException, GeneralNamesException {
+ if (size() == 0) {
+ return;
+ }
+
+ Enumeration<GeneralNameInterface> names = elements();
+ DerOutputStream temp = new DerOutputStream();
+
+ while (names.hasMoreElements()) {
+ Object obj = names.nextElement();
+ if (!(obj instanceof GeneralNameInterface)) {
+ throw new GeneralNamesException("Element in GeneralNames "
+ + "not of type GeneralName.");
+ }
+ GeneralNameInterface intf = (GeneralNameInterface) obj;
+ if (obj instanceof GeneralName) {
+ intf.encode(temp);
+ } else {
+ DerOutputStream gname = new DerOutputStream();
+ intf.encode(gname);
+ int nameType = intf.getType();
+ // constructed form
+ if (nameType == GeneralNameInterface.NAME_ANY ||
+ nameType == GeneralNameInterface.NAME_X400 ||
+ nameType == GeneralNameInterface.NAME_EDI) {
+
+ temp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) nameType), gname);
+ } else if (nameType == GeneralNameInterface.NAME_DIRECTORY) {
+ // EXPLICIT tag because directoryName is a CHOICE
+ temp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte) nameType), gname);
+ } else
+ // primitive form
+ temp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, (byte) nameType), gname);
+ }
+
+ }
+
+ out.write(DerValue.tag_Sequence, temp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/GeneralNamesException.java b/base/util/src/netscape/security/x509/GeneralNamesException.java
new file mode 100644
index 000000000..6309ed114
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralNamesException.java
@@ -0,0 +1,50 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * Generic General Names Exception.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class GeneralNamesException extends GeneralSecurityException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8320001725384815795L;
+
+ /**
+ * Constructs a GeneralNamesException with no detail message.
+ */
+ public GeneralNamesException() {
+ super();
+ }
+
+ /**
+ * Constructs the exception with the specified error message.
+ *
+ * @param message the requisite error message.
+ */
+ public GeneralNamesException(String message) {
+ super(message);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/GeneralSubtree.java b/base/util/src/netscape/security/x509/GeneralSubtree.java
new file mode 100644
index 000000000..635427e0b
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralSubtree.java
@@ -0,0 +1,159 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.PrettyPrintFormat;
+
+/**
+ * Represent the GeneralSubtree ASN.1 object, whose syntax is:
+ *
+ * <pre>
+ * GeneralSubtree ::= SEQUENCE {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL
+ * }
+ * BaseDistance ::= INTEGER (0..MAX)
+ * </pre>
+ *
+ * @version 1.5
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class GeneralSubtree {
+ private static final byte TAG_MIN = 0;
+ private static final byte TAG_MAX = 1;
+ private static final int MIN_DEFAULT = 0;
+
+ private GeneralName name;
+ private int minimum = MIN_DEFAULT;
+ private int maximum = -1;
+
+ private PrettyPrintFormat pp = new PrettyPrintFormat(":");
+
+ /**
+ * The default constructor for the class.
+ *
+ * @param name the GeneralName
+ * @param min the minimum BaseDistance
+ * @param max the maximum BaseDistance
+ */
+ public GeneralSubtree(GeneralName name, int min, int max) {
+ this.name = name;
+ this.minimum = min;
+ this.maximum = max;
+ }
+
+ /**
+ * Create the object from its DER encoded form.
+ *
+ * @param val the DER encoded from of the same.
+ */
+ public GeneralSubtree(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for GeneralSubtree.");
+ }
+ name = new GeneralName(val.data.getDerValue());
+
+ // NB. this is always encoded with the IMPLICIT tag
+ // The checks only make sense if we assume implicit tagging,
+ // with explicit tagging the form is always constructed.
+ while (val.data.available() != 0) {
+ DerValue opt = val.data.getDerValue();
+
+ if (opt.isContextSpecific(TAG_MIN) && !opt.isConstructed()) {
+ opt.resetTag(DerValue.tag_Integer);
+ minimum = (opt.getInteger()).toInt();
+
+ } else if (opt.isContextSpecific(TAG_MAX) && !opt.isConstructed()) {
+ opt.resetTag(DerValue.tag_Integer);
+ maximum = (opt.getInteger()).toInt();
+ } else
+ throw new IOException("Invalid encoding of GeneralSubtree.");
+ }
+ }
+
+ /**
+ * Return a printable string of the GeneralSubtree.
+ */
+ public String toString() {
+ String s = "\n GeneralSubtree: [\n" +
+ " GeneralName: " + ((name == null) ? "" : name.toString()) +
+ "\n Minimum: " + minimum;
+ if (maximum == -1) {
+ s += "\t Maximum: undefined";
+ } else
+ s += "\t Maximum: " + maximum;
+ s += " ]\n";
+ return (s);
+ }
+
+ public String toPrint(int indent) {
+ String s = "\n" + pp.indent(indent) + "GeneralSubtree: [\n" + pp.indent(indent + 2) +
+ "GeneralName: " + ((name == null) ? "" : name.toString()) +
+ "\n" + pp.indent(indent + 2) + "Minimum: " + minimum;
+ if (maximum == -1) {
+ s += "\n" + pp.indent(indent + 2) + "Maximum: undefined";
+ } else
+ s += "\n" + pp.indent(indent + 2) + "Maximum: " + maximum;
+ s += "]\n";
+ return (s);
+ }
+
+ /**
+ * Encode the GeneralSubtree.
+ *
+ * @param out the DerOutputStream to encode this object to.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+
+ name.encode(seq);
+
+ if (minimum != MIN_DEFAULT) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(minimum));
+ seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_MIN), tmp);
+ }
+ if (maximum != -1) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(maximum));
+ seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_MAX), tmp);
+ }
+ out.write(DerValue.tag_Sequence, seq);
+ }
+
+ public GeneralName getGeneralName() {
+ return name;
+ }
+
+ public int getMaxValue() {
+ return maximum;
+ }
+
+ public int getMinValue() {
+ return minimum;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/GeneralSubtrees.java b/base/util/src/netscape/security/x509/GeneralSubtrees.java
new file mode 100644
index 000000000..37097ca71
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GeneralSubtrees.java
@@ -0,0 +1,106 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.PrettyPrintFormat;
+
+/**
+ * Represent the GeneralSubtrees ASN.1 object.
+ *
+ * @version 1.4
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class GeneralSubtrees {
+ private Vector<GeneralSubtree> trees;
+ private PrettyPrintFormat pp = new PrettyPrintFormat(":");
+
+ /**
+ * The default constructor for the class.
+ *
+ * @param trees the sequence of GeneralSubtree.
+ */
+ public GeneralSubtrees(Vector<GeneralSubtree> trees) {
+ this.trees = trees;
+ }
+
+ /**
+ * Create the object from the passed DER encoded form.
+ *
+ * @param val the DER encoded form of the same.
+ */
+ public GeneralSubtrees(DerValue val) throws IOException {
+ trees = new Vector<GeneralSubtree>(1, 1);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of GeneralSubtrees.");
+ }
+ while (val.data.available() != 0) {
+ DerValue opt = val.data.getDerValue();
+ GeneralSubtree tree = new GeneralSubtree(opt);
+ trees.addElement(tree);
+ }
+ }
+
+ /**
+ * Return a printable string of the GeneralSubtree.
+ */
+ public String toString() {
+ String s = " GeneralSubtrees:\n" + trees.toString()
+ + "\n";
+
+ return (s);
+ }
+
+ public String toPrint(int indent) {
+
+ String s = "";
+ GeneralSubtree element;
+
+ for (Enumeration<GeneralSubtree> e = trees.elements(); e.hasMoreElements();) {
+ element = (GeneralSubtree) e.nextElement();
+ s = s + pp.indent(indent + 4) + element.toPrint(indent) + "\n";
+ }
+
+ return (s);
+ }
+
+ /**
+ * Encode the GeneralSubtrees.
+ *
+ * @param out the DerOutputStrean to encode this object to.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+
+ for (int i = 0; i < trees.size(); i++) {
+ ((GeneralSubtree) trees.elementAt(i)).encode(seq);
+ }
+ out.write(DerValue.tag_Sequence, seq);
+ }
+
+ public Vector<GeneralSubtree> getSubtrees() {
+ return trees;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/GenericValueConverter.java b/base/util/src/netscape/security/x509/GenericValueConverter.java
new file mode 100644
index 000000000..73bc1979c
--- /dev/null
+++ b/base/util/src/netscape/security/x509/GenericValueConverter.java
@@ -0,0 +1,143 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+
+import netscape.security.util.ASN1CharStrConvMap;
+import netscape.security.util.DerValue;
+
+/**
+ * A GenericValueConverter converts a string that is not associated with
+ * a particular attribute to a DER encoded ASN.1 character string type.
+ * Currently supports PrintableString, IA5String, BMPString T.61String and
+ * Universal String.
+ *
+ * <p>
+ * The conversion is done as follows. An encoder is obtained for the all the character sets from the global default
+ * ASN1CharStrConvMap. The encoders are then used to convert the string to the smallest character set first --
+ * printableString. If the string contains characters outside of that character set, it is converted to the next
+ * character set -- IA5String character set. If that is not enough it is converted to a BMPString, then Universal String
+ * which contains all characters.
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ *
+ */
+
+public class GenericValueConverter implements AVAValueConverter {
+ public GenericValueConverter() {
+ }
+
+ /**
+ * Converts a string to a DER encoded ASN.1 primtable string, defined here
+ * as a PrintableString, IA5String, T.61String, BMPString or
+ * UniversalString. The string is not expected to be encoded in any form.
+ *
+ * <p>
+ * If an encoder is not available for a character set that is needed to convert the string, the string cannot be
+ * converted and an IOException is thrown. For example, if the string contains characters outside the
+ * PrintableString character and only a PrintableString encoder is available then an IOException is thrown.
+ *
+ * @param s A string representing a generic attribute string value.
+ *
+ * @return The DER value of the attribute.
+ *
+ * @exception IOException if the string cannot be converted, such as
+ * when an encoder needed is
+ * unavailable.
+ */
+ public DerValue getValue(String s)
+ throws IOException {
+ return getValue(s, null);
+ }
+
+ public DerValue getValue(String valueString, byte[] tags) throws IOException {
+ // try to convert to printable, then t61 the universal -
+ // i.e. from minimal coverage to the broadest.
+
+ if (tags == null || tags.length == 0)
+ tags = DefEncodingTags;
+
+ for (int i = 0; i < tags.length; i++) {
+ try {
+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tags[i]);
+ if (encoder == null)
+ continue;
+
+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray());
+ ByteBuffer byteBuffer = encoder.encode(charBuffer);
+
+ return new DerValue(tags[i], byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit());
+
+ } catch (CharacterCodingException e) {
+ continue;
+ }
+ }
+
+ throw new IOException(
+ "Cannot convert the string value to a ASN.1 type");
+ }
+
+ /**
+ * Creates a DerValue from the byte array of BER encoded value.
+ *
+ * NOTE: currently only supports DER encoding (a form of BER) on input .
+ *
+ * @param berStream Byte array of a BER encoded value.
+ *
+ * @return DerValue object.
+ *
+ * @exception IOException If the BER value cannot be converted to a
+ * valid Directory String DER value.
+ */
+ public DerValue getValue(byte[] berByteStream)
+ throws IOException {
+ // accepts any tag.
+ DerValue value = new DerValue(berByteStream);
+ return value;
+ }
+
+ /**
+ * Converts a DerValue of ASN1 Character string type to a java string
+ * (the string is not encoded in any form).
+ *
+ * @param avaValue A DerValue
+ * @return A string representing the attribute value.
+ * @exception IOException if a decoder needed for the
+ * conversion is not available or if BER value
+ * is not one of the ASN1 character string types
+ * here.
+ */
+ public String getAsString(DerValue avaValue)
+ throws IOException {
+ return avaValue.getASN1CharString();
+ }
+
+ private static byte DefEncodingTags[] = {
+ DerValue.tag_PrintableString,
+ DerValue.tag_IA5String,
+ DerValue.tag_BMPString,
+ DerValue.tag_UTF8String,
+ DerValue.tag_T61String,
+ DerValue.tag_UniversalString
+ };
+}
diff --git a/base/util/src/netscape/security/x509/HoldInstructionExtension.java b/base/util/src/netscape/security/x509/HoldInstructionExtension.java
new file mode 100644
index 000000000..b42bb6ac9
--- /dev/null
+++ b/base/util/src/netscape/security/x509/HoldInstructionExtension.java
@@ -0,0 +1,354 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Represent the CRL Hold Instruction Code Extension.
+ *
+ * <p>
+ * The hold instruction code is a non-critical CRL entry extension that provides a registered instruction identifier
+ * which indicates the action to be taken after encountering a certificate that has been placed on hold.
+ *
+ * @see Extension
+ * @see CertAttrSet
+ */
+
+public class HoldInstructionExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6706557233070964984L;
+ /**
+ * Attribute name.
+ */
+ public static final String NAME = "HoldInstruction";
+ public static final String HOLD_INSTRUCTION = "value";
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.23";
+
+ public static final String NONE_HOLD_INSTR_OID_STR =
+ "1.2.840.10040.2.1";
+ public static final ObjectIdentifier NONE_HOLD_INSTR_OID =
+ new ObjectIdentifier(NONE_HOLD_INSTR_OID_STR);
+
+ public static final String CALL_ISSUER_HOLD_INSTR_OID_STR =
+ "1.2.840.10040.2.2";
+ public static final ObjectIdentifier CALL_ISSUER_HOLD_INSTR_OID =
+ new ObjectIdentifier(CALL_ISSUER_HOLD_INSTR_OID_STR);
+
+ public static final String REJECT_HOLD_INSTR_OID_STR =
+ "1.2.840.10040.2.3";
+ public static final ObjectIdentifier REJECT_HOLD_INSTR_OID =
+ new ObjectIdentifier(REJECT_HOLD_INSTR_OID_STR);
+
+ private ObjectIdentifier holdInstructionCodeOIDs[] = { NONE_HOLD_INSTR_OID,
+ CALL_ISSUER_HOLD_INSTR_OID,
+ REJECT_HOLD_INSTR_OID };
+ private ObjectIdentifier holdInstructionCodeOID = null;
+
+ private String holdInstructionDescription[] = { "None",
+ "Call Issuer",
+ "Reject" };
+
+ static {
+ try {
+ OIDMap.addAttribute(HoldInstructionExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ private int getHoldInstructionCodeFromOID(ObjectIdentifier oid) {
+ for (int i = 0; i < holdInstructionCodeOIDs.length; i++) {
+ if (oid.equals(holdInstructionCodeOIDs[i]))
+ return (i + 1);
+ }
+ return 0;
+ }
+
+ private String getHoldInstructionDescription(ObjectIdentifier oid) {
+ String description = "Invalid";
+ if (oid != null) {
+ int i = getHoldInstructionCodeFromOID(oid);
+ if (i > 0 && i < 4)
+ description = holdInstructionDescription[i - 1];
+ }
+ return (description);
+ }
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ if (holdInstructionCodeOID == null)
+ throw new IOException("Unintialized hold instruction extension");
+ DerOutputStream os = new DerOutputStream();
+ os.putOID(holdInstructionCodeOID);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param code the value to be set for the extension.
+ */
+ public HoldInstructionExtension(int code)
+ throws IOException {
+ if (code < 1 || code > 3)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = holdInstructionCodeOIDs[code - 1];
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param oidStr the value to be set for the extension.
+ */
+ public HoldInstructionExtension(String oidStr)
+ throws IOException {
+ ObjectIdentifier oid = new ObjectIdentifier(oidStr);
+ if (oid == null || getHoldInstructionCodeFromOID(oid) == 0)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = oid;
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param oid the value to be set for the extension.
+ */
+ public HoldInstructionExtension(ObjectIdentifier oid)
+ throws IOException {
+ if (getHoldInstructionCodeFromOID(oid) == 0)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = oid;
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param code the value to be set for the extension.
+ */
+ public HoldInstructionExtension(Boolean critical, int code)
+ throws IOException {
+ if (code < 1 || code > 3)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = holdInstructionCodeOIDs[code - 1];
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param oidStr the value to be set for the extension.
+ */
+ public HoldInstructionExtension(Boolean critical, String oidStr)
+ throws IOException {
+ ObjectIdentifier oid = new ObjectIdentifier(oidStr);
+ if (oid == null || getHoldInstructionCodeFromOID(oid) == 0)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = oid;
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create a HoldInstructionExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param oid the value to be set for the extension.
+ */
+ public HoldInstructionExtension(Boolean critical, ObjectIdentifier oid)
+ throws IOException {
+ if (getHoldInstructionCodeFromOID(oid) == 0)
+ throw new IOException("Invalid hold instruction code");
+ holdInstructionCodeOID = oid;
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public HoldInstructionExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag == DerValue.tag_ObjectId) {
+ DerInputStream derInputStream = new DerInputStream(val.toByteArray());
+ holdInstructionCodeOID = derInputStream.getOID();
+ if (getHoldInstructionCodeFromOID(holdInstructionCodeOID) == 0)
+ throw new IOException("Invalid encoding for HoldInstructionExtension");
+ } else {
+ throw new IOException("Invalid encoding for HoldInstructionExtension");
+ }
+ }
+
+ /**
+ * Get the hold instruction code.
+ */
+ public ObjectIdentifier getHoldInstructionCode() {
+ return holdInstructionCodeOID;
+ }
+
+ public String getHoldInstructionCodeDescription() {
+ return getHoldInstructionDescription(holdInstructionCodeOID);
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) {
+ if (!(obj instanceof ObjectIdentifier)) {
+ throw new IOException("Attribute must be of type String.");
+ }
+ holdInstructionCodeOID = (ObjectIdentifier) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:HoldInstructionCode.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) {
+ return holdInstructionCodeOID;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:HoldInstructionCode.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) {
+ holdInstructionCodeOID = null;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:HoldInstructionCode.");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the HoldInstructionExtension.
+ */
+ public String toString() {
+ String s = super.toString() + "Hold Instruction Code: " +
+ getHoldInstructionDescription(holdInstructionCodeOID) + "\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id;
+ this.critical = true;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(HOLD_INSTRUCTION);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/IA5StringConverter.java b/base/util/src/netscape/security/x509/IA5StringConverter.java
new file mode 100644
index 000000000..eced75a58
--- /dev/null
+++ b/base/util/src/netscape/security/x509/IA5StringConverter.java
@@ -0,0 +1,123 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+
+import netscape.security.util.ASN1CharStrConvMap;
+import netscape.security.util.DerValue;
+
+/**
+ * A AVAValueConverter that converts a IA5String attribute to a DerValue
+ * and vice versa. An example an attribute that is a IA5String string is "E".
+ *
+ * @see AVAValueConverter
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public class IA5StringConverter implements AVAValueConverter {
+ // public constructors
+
+ /*
+ * Contructs a IA5String Converter.
+ */
+ public IA5StringConverter() {
+ }
+
+ /*
+ * Converts a string with ASN.1 IA5String characters to a DerValue.
+ *
+ * @param valueString a string with IA5String characters.
+ *
+ * @return a DerValue.
+ *
+ * @exception IOException if a IA5String encoder is not
+ * available for the conversion.
+ */
+ public DerValue getValue(String valueString)
+ throws IOException {
+ return getValue(valueString, null);
+ }
+
+ public DerValue getValue(String valueString, byte[] tags) throws IOException {
+ try {
+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(DerValue.tag_IA5String);
+ if (encoder == null)
+ throw new IOException("No encoder for IA5String");
+
+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray());
+ ByteBuffer byteBuffer = encoder.encode(charBuffer);
+
+ return new DerValue(DerValue.tag_IA5String,
+ byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit());
+
+ } catch (CharacterCodingException e) {
+ throw new IllegalArgumentException("Invalid IA5String AVA Value string");
+ }
+ }
+
+ /*
+ * Converts a BER encoded value of IA5String to a DER encoded value.
+ * Checks if the BER encoded value is a IA5String.
+ * NOTE only DER encoding is currently supported on for the BER
+ * encoded value.
+ *
+ * @param berStream a byte array of the BER encoded value.
+ *
+ * @return a DerValue.
+ *
+ * @exception IOException if the BER value cannot be converted
+ * to a IA5String DER value.
+ */
+ public DerValue getValue(byte[] berStream)
+ throws IOException {
+ DerValue value = new DerValue(berStream);
+ if (value.tag == DerValue.tag_IA5String)
+ return value;
+ if (value.tag == DerValue.tag_PrintableString)
+ return value;
+ throw new IOException("Invalid IA5String AVA Value.");
+ }
+
+ /*
+ * Converts a DerValue of IA5String to a java string with IA5String
+ * characters.
+ *
+ * @param avaValue a DerValue.
+ *
+ * @return a string with IA5String characters.
+ *
+ * @exception IOException if the DerValue is not a IA5String i.e.
+ * The DerValue cannot be converted to a string
+ * with IA5String characters.
+ */
+ public String getAsString(DerValue avaValue)
+ throws IOException {
+ if (avaValue.tag == DerValue.tag_IA5String)
+ return avaValue.getIA5String();
+ if (avaValue.tag == DerValue.tag_PrintableString)
+ return avaValue.getPrintableString();
+ throw new IOException("Invalid IA5String AVA Value.");
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/IPAddressName.java b/base/util/src/netscape/security/x509/IPAddressName.java
new file mode 100644
index 000000000..75b5bc564
--- /dev/null
+++ b/base/util/src/netscape/security/x509/IPAddressName.java
@@ -0,0 +1,277 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the IPAddressName as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * @see GeneralName
+ * @see GeneralNameInterface
+ * @see GeneralNames
+ *
+ * @version 1.2
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class IPAddressName implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4240184399679453666L;
+ private byte[] address;
+
+ /**
+ * Create the IPAddressName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER IPAddressName.
+ * @exception IOException on error.
+ */
+ public IPAddressName(DerValue derValue) throws IOException {
+ address = derValue.getOctetString();
+ }
+
+ /**
+ * Create the IPAddressName object with the specified name.
+ *
+ * @param name the IPAddressName.
+ */
+ public IPAddressName(byte[] address) {
+ this.address = address;
+ }
+
+ protected static final char IPv4_LEN = 4;
+ protected static final char IPv6_LEN = 16;
+ protected static final IPAddr IPv4 = new IPv4Addr();
+ protected static final IPAddr IPv6 = new IPv6Addr();
+
+ /**
+ * Create the IPAddressName object with a string representing the
+ * ip address and a string representing the netmask, with encoding
+ * having ip address encoding followed by the netmask encoding.
+ * This form is needed for name constraints extension.
+ *
+ * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884)
+ * @param netmask the netmask address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884)
+ */
+ public IPAddressName(String s, String netmask) {
+ // Based on PKIX RFC2459. IPAddress has
+ // 8 bytes (instead of 4 bytes) in the
+ // context of NameConstraints
+ IPAddr ipAddr = null;
+ if (s.indexOf(':') != -1) {
+ ipAddr = IPv6;
+ address = new byte[IPv6_LEN * 2];
+ } else {
+ ipAddr = IPv4;
+ address = new byte[IPv4_LEN * 2];
+ }
+ StringTokenizer st = new StringTokenizer(s, ",");
+ int numFilled = ipAddr.getIPAddr(st.nextToken(), address, 0);
+ if (st.hasMoreTokens()) {
+ ipAddr.getIPAddr(st.nextToken(), address, numFilled);
+ } else {
+ for (int i = numFilled; i < address.length; i++)
+ address[i] = (byte) 0xff;
+ }
+ }
+
+ /**
+ * Create the IPAddressName object with a string representing the
+ * ip address.
+ *
+ * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x
+ */
+ public IPAddressName(String s) {
+ IPAddr ipAddr = null;
+ if (s.indexOf(':') != -1) {
+ ipAddr = IPv6;
+ address = new byte[IPv6_LEN];
+ } else {
+ ipAddr = IPv4;
+ address = new byte[IPv4_LEN];
+ }
+ ipAddr.getIPAddr(s, address, 0);
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_IP);
+ }
+
+ /**
+ * Encode the IPAddress name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the IPAddressName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putOctetString(address);
+ }
+
+ /**
+ * Return a printable string of IPaddress
+ */
+ public String toString() {
+ if (address.length == 4) {
+ return ("IPAddress: " + (address[0] & 0xff) + "."
+ + (address[1] & 0xff) + "."
+ + (address[2] & 0xff) + "." + (address[3] & 0xff));
+ } else {
+ String r = "IPAddress: " + Integer.toHexString(address[0] & 0xff);
+ String hexString = Integer.toHexString(address[1] & 0xff);
+ if (hexString.length() == 1) {
+ r = r + "0" + hexString;
+ } else {
+ r += hexString;
+ }
+ for (int i = 2; i < address.length;) {
+ r += ":" + Integer.toHexString(address[i] & 0xff);
+ hexString = Integer.toHexString(address[i + 1] & 0xff);
+ if (hexString.length() == 1) {
+ r = r + "0" + hexString;
+ } else {
+ r += hexString;
+ }
+ i += 2;
+ }
+ return r;
+ }
+ }
+}
+
+interface IPAddr {
+ public int getIPAddr(String s, byte[] address, int start);
+
+ public int getLength();
+}
+
+class IPv4Addr implements IPAddr {
+ protected static final int IPv4_LEN = 4;
+
+ /**
+ * Gets an IP v4 address in the form n.n.n.n.
+ */
+ public int getIPAddr(String s, byte[] address, int start) {
+ StringTokenizer st = new StringTokenizer(s, ".");
+ int nt = st.countTokens();
+ if (nt != IPv4_LEN)
+ throw new InvalidIPAddressException(s);
+ try {
+ int end = start + nt;
+ for (int i = start; i < end; i++) {
+ Integer j = new Integer(st.nextToken());
+ address[i] = (byte) j.intValue();
+ }
+ } catch (NumberFormatException e) {
+ throw new InvalidIPAddressException(s);
+ }
+ return nt;
+ }
+
+ public int getLength() {
+ return IPv4_LEN;
+ }
+}
+
+class IPv6Addr implements IPAddr {
+ /**
+ * Gets an IP address in the forms as defined in RFC1884:<br>
+ * <ul>
+ * <li>x:x:x:x:x:x:x:x
+ * <li>...::xxx (using :: shorthand)
+ * <li>...:n.n.n.n (with n.n.n.n at the end)
+ * </ul>
+ */
+ public int getIPAddr(String s, byte[] address, int start) {
+ int lastcolon = -2;
+ int end = start + 16;
+ int idx = start;
+ for (int i = start; i < address.length; i++)
+ address[i] = 0;
+ if (s.indexOf('.') != -1) { // has n.n.n.n at the end
+ lastcolon = s.lastIndexOf(':');
+ if (lastcolon == -1)
+ throw new InvalidIPAddressException(s);
+ end -= 4;
+ IPAddressName.IPv4.getIPAddr(
+ s.substring(lastcolon + 1), address, end);
+ }
+ try {
+ String s1 = s;
+ if (lastcolon != -2)
+ s1 = s.substring(0, lastcolon + 1);
+ int lastDoubleColon = s1.indexOf("::");
+ String l = s1, r = null;
+ StringTokenizer lt = null, rt = null;
+ if (lastDoubleColon != -1) {
+ l = s1.substring(0, lastDoubleColon);
+ r = s1.substring(lastDoubleColon + 2);
+ if (l.length() == 0)
+ l = null;
+ if (r.length() == 0)
+ r = null;
+ }
+ int at = 0;
+ if (l != null) {
+ lt = new StringTokenizer(l, ":", false);
+ at += lt.countTokens();
+ }
+ if (r != null) {
+ rt = new StringTokenizer(r, ":", false);
+ at += rt.countTokens();
+ }
+ if (at > 8 ||
+ (lastcolon != -2 && (at > 6 || (lastDoubleColon == -1 && at != 6))))
+ throw new InvalidIPAddressException(s);
+ if (l != null) {
+ while (lt.hasMoreTokens()) {
+ String tok = lt.nextToken();
+ int j = Integer.parseInt(tok, 16);
+ address[idx++] = (byte) ((j >> 8) & 0xFF);
+ address[idx++] = (byte) (j & 0xFF);
+ }
+ }
+ if (r != null) {
+ idx = end - (rt.countTokens() * 2);
+ while (rt.hasMoreTokens()) {
+ String tok = rt.nextToken();
+ int j = Integer.parseInt(tok, 16);
+ address[idx++] = (byte) ((j >> 8) & 0xFF);
+ address[idx++] = (byte) (j & 0xFF);
+ }
+ }
+ } catch (NumberFormatException e) {
+ throw new InvalidIPAddressException(s);
+ }
+ return 16;
+ }
+
+ public int getLength() {
+ return 16;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/InvalidIPAddressException.java b/base/util/src/netscape/security/x509/InvalidIPAddressException.java
new file mode 100644
index 000000000..f544df200
--- /dev/null
+++ b/base/util/src/netscape/security/x509/InvalidIPAddressException.java
@@ -0,0 +1,33 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+public class InvalidIPAddressException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1601934234587845028L;
+
+ public InvalidIPAddressException() {
+ super();
+ }
+
+ public InvalidIPAddressException(String ip) {
+ super("Invalid IP Address '" + ip + "'");
+ }
+}
diff --git a/base/util/src/netscape/security/x509/InvalidityDateExtension.java b/base/util/src/netscape/security/x509/InvalidityDateExtension.java
new file mode 100755
index 000000000..44c76275f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/InvalidityDateExtension.java
@@ -0,0 +1,241 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CRL Invalidity Date Extension.
+ *
+ * <p>
+ * This CRL entry extension, if present, provides the date on which it is known or suspected that the private key was
+ * compromised or that the certificate otherwise became invalid. Invalidity date may be earlier than the revocation
+ * date.
+ *
+ * @see Extension
+ * @see CertAttrSet
+ */
+
+public class InvalidityDateExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2191026017389643053L;
+ /**
+ * Attribute name.
+ */
+ public static final String NAME = "InvalidityDate";
+ public static final String INVALIDITY_DATE = "value";
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.24";
+
+ private Date invalidityDate = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(InvalidityDateExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ if (invalidityDate == null)
+ throw new IOException("Unintialized invalidity date extension");
+ DerOutputStream os = new DerOutputStream();
+ os.putGeneralizedTime(this.invalidityDate);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a InvalidityDateExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param dateOfInvalidity the value to be set for the extension.
+ */
+ public InvalidityDateExtension(Date dateOfInvalidity)
+ throws IOException {
+ this.invalidityDate = dateOfInvalidity;
+ this.extensionId = PKIXExtensions.InvalidityDate_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a InvalidityDateExtension with the date.
+ * The criticality is set to false.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param dateOfInvalidity the value to be set for the extension.
+ */
+ public InvalidityDateExtension(Boolean critical, Date dateOfInvalidity)
+ throws IOException {
+ this.invalidityDate = dateOfInvalidity;
+ this.extensionId = PKIXExtensions.InvalidityDate_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public InvalidityDateExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.InvalidityDate_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag == DerValue.tag_GeneralizedTime) {
+ DerInputStream derInputStream = new DerInputStream(val.toByteArray());
+ this.invalidityDate = derInputStream.getGeneralizedTime();
+ } else {
+ throw new IOException("Invalid encoding for InvalidityDateExtension");
+ }
+ }
+
+ /**
+ * Get the invalidity date.
+ */
+ public Date getInvalidityDate() {
+ return invalidityDate;
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) {
+ if (!(obj instanceof Date)) {
+ throw new IOException("Attribute must be of type Date.");
+ }
+ invalidityDate = (Date) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:InvalidityDate.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) {
+ if (invalidityDate == null)
+ return null;
+ else
+ return invalidityDate;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:InvalidityDate.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) {
+ invalidityDate = null;
+ } else {
+ throw new IOException("Attribute name not recognized by" +
+ " CertAttrSet:InvalidityDate.");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the InvalidityDateExtension.
+ */
+ public String toString() {
+ String s = super.toString() + "Invalidity Date: " +
+ ((invalidityDate == null) ? "" : invalidityDate.toString())
+ + "\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.InvalidityDate_Id;
+ this.critical = true;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(INVALIDITY_DATE);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/IssuerAlternativeNameExtension.java b/base/util/src/netscape/security/x509/IssuerAlternativeNameExtension.java
new file mode 100644
index 000000000..df0289f9e
--- /dev/null
+++ b/base/util/src/netscape/security/x509/IssuerAlternativeNameExtension.java
@@ -0,0 +1,240 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This represents the Issuer Alternative Name Extension.
+ *
+ * This extension, if present, allows the issuer to specify multiple
+ * alternative names.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class IssuerAlternativeNameExtension
+ extends Extension implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -269518027483586255L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT =
+ "x509.info.extensions.IssuerAlternativeName";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "IssuerAlternativeName";
+ public static final String ISSUER_NAME = "issuer_name";
+
+ // private data members
+ GeneralNames names;
+
+ // Encode this extension
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ try {
+ names.encode(os);
+ } catch (GeneralNamesException e) {
+ throw new IOException(e.toString());
+ }
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a IssuerAlternativeNameExtension with the passed GeneralNames.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param names the GeneralNames for the issuer.
+ * @exception IOException on error.
+ */
+ public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+ this.critical = critical.booleanValue();
+ encodeThis();
+ }
+
+ /**
+ * Create a IssuerAlternativeNameExtension with the passed GeneralNames.
+ *
+ * @param names the GeneralNames for the issuer.
+ * @exception IOException on error.
+ */
+ public IssuerAlternativeNameExtension(GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a default IssuerAlternativeNameExtension.
+ */
+ public IssuerAlternativeNameExtension() {
+ extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+ critical = false;
+ names = new GeneralNames();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public IssuerAlternativeNameExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ try {
+ names = new GeneralNames(val);
+ } catch (GeneralNamesException e) {
+ throw new IOException("IssuerAlternativeNameExtension"
+ + e.toString());
+ }
+ }
+
+ /**
+ * Returns a printable representation of the IssuerAlternativeName.
+ */
+ public String toString() {
+ if (names == null)
+ return "";
+ String s = super.toString() + "IssuerAlternativeName [\n"
+ + names.toString() + "]\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding error.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(ISSUER_NAME)) {
+ if (!(obj instanceof GeneralNames)) {
+ throw new IOException("Attribute value should be of" +
+ " type GeneralNames.");
+ }
+ names = (GeneralNames) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuerAlternativeName.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(ISSUER_NAME)) {
+ return (names);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuerAlternativeName.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(ISSUER_NAME)) {
+ names = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuerAlternativeName.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(ISSUER_NAME);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/IssuingDistributionPoint.java b/base/util/src/netscape/security/x509/IssuingDistributionPoint.java
new file mode 100644
index 000000000..0f0747f84
--- /dev/null
+++ b/base/util/src/netscape/security/x509/IssuingDistributionPoint.java
@@ -0,0 +1,315 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BOOLEAN;
+import org.mozilla.jss.asn1.EXPLICIT;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * <pre>
+ * issuingDistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
+ * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
+ * onlySomeReasons [3] ReasonFlags OPTIONAL,
+ * indirectCRL [4] BOOLEAN DEFAULT FALSE }
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6) }
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ *
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * </pre>
+ *
+ * See the documentation in <code>CRLDistributionPoint</code> for
+ * the <code>DistributionPointName</code> and <code>ReasonFlags</code> ASN.1 types.
+ */
+public class IssuingDistributionPoint implements ASN1Value {
+
+ // at most one of the following two may be specified. One or both can
+ // be null.
+ private GeneralNames fullName = null;
+ private RDN relativeName = null;
+
+ private boolean onlyContainsUserCerts = false; // DEFAULT FALSE
+ private boolean onlyContainsCACerts = false; // DEFAULT FALSE
+ private BitArray onlySomeReasons = null; // optional, may be null
+ private boolean indirectCRL = false; // DEFAULT FALSE
+
+ // cache encoding of fullName
+ private ANY fullNameEncoding;
+
+ /**
+ * Returns the <code>fullName</code> of the <code>DistributionPointName</code>, which may be <code>null</code>.
+ */
+ public GeneralNames getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Returns the <code>relativeName</code> of the <code>DistributionPointName</code>, which may be <code>null</code>.
+ */
+ public RDN getRelativeName() {
+ return relativeName;
+ }
+
+ /**
+ * Sets the <code>fullName</code> of the <code>DistributionPointName</code>. It may be set to <code>null</code>.
+ * If it is set to a non-null value, <code>relativeName</code> will be
+ * set to <code>null</code>, because at most one of these two attributes
+ * can be specified at a time.
+ *
+ * @exception GeneralNamesException If an error occurs encoding the
+ * name.
+ */
+ public void setFullName(GeneralNames fullName)
+ throws GeneralNamesException, IOException {
+ this.fullName = fullName;
+ if (fullName != null) {
+ // encode the name to catch any problems with it
+ DerOutputStream derOut = new DerOutputStream();
+ fullName.encode(derOut);
+ try {
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(0), bos);
+ fullNameEncoding = new ANY(bos.toByteArray());
+ } catch (InvalidBERException e) {
+ // assume this won't happen, since it would imply a bug
+ // in DerOutputStream
+ throw new GeneralNamesException(e.toString());
+ }
+
+ this.relativeName = null;
+ }
+ }
+
+ /**
+ * Sets the <code>relativeName</code> of the <code>DistributionPointName</code>. It may be set to <code>null</code>.
+ * If it is set to a non-null value, <code>fullName</code> will be
+ * set to <code>null</code>, because at most one of these two attributes
+ * can be specified at a time.
+ */
+ public void setRelativeName(RDN relativeName) {
+ this.relativeName = relativeName;
+ if (relativeName != null) {
+ this.fullName = null;
+ }
+ }
+
+ public boolean getOnlyContainsUserCerts() {
+ return onlyContainsUserCerts;
+ }
+
+ public void setOnlyContainsUserCerts(boolean b) {
+ onlyContainsUserCerts = b;
+ }
+
+ public boolean getOnlyContainsCACerts() {
+ return onlyContainsCACerts;
+ }
+
+ public void setOnlyContainsCACerts(boolean b) {
+ onlyContainsCACerts = b;
+ }
+
+ /**
+ * Returns the reason flags for this distribution point. May be <code>null</code>.
+ */
+ public BitArray getOnlySomeReasons() {
+ return onlySomeReasons;
+ }
+
+ /**
+ * Sets the reason flags for this distribution point. May be set to <code>null</code>.
+ */
+ public void setOnlySomeReasons(BitArray reasons) {
+ this.onlySomeReasons = reasons;
+ }
+
+ public boolean getIndirectCRL() {
+ return indirectCRL;
+ }
+
+ public void setIndirectCRL(boolean b) {
+ indirectCRL = b;
+ }
+
+ /////////////////////////////////////////////////////////////
+ // DER encoding
+ /////////////////////////////////////////////////////////////
+ private static final Tag TAG = SEQUENCE.TAG;
+
+ public Tag getTag() {
+ return TAG;
+ }
+
+ public void encode(OutputStream ostream) throws IOException {
+ encode(TAG, ostream);
+ }
+
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException {
+
+ SEQUENCE seq = new SEQUENCE();
+ DerOutputStream derOut;
+
+ try {
+
+ // Encodes the DistributionPointName. Because DistributionPointName
+ // is a CHOICE, the [0] tag is forced to be EXPLICIT.
+ if (fullName != null) {
+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), fullNameEncoding);
+ seq.addElement(distPoint);
+ } else if (relativeName != null) {
+ derOut = new DerOutputStream();
+ relativeName.encode(derOut);
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(1), bos);
+ ANY distPointName = new ANY(bos.toByteArray());
+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), distPointName);
+ seq.addElement(distPoint);
+ }
+
+ if (onlyContainsUserCerts != false) {
+ seq.addElement(Tag.get(1), new BOOLEAN(true));
+ }
+ if (onlyContainsCACerts != false) {
+ seq.addElement(Tag.get(2), new BOOLEAN(true));
+ }
+
+ // Encodes the ReasonFlags.
+ if (onlySomeReasons != null) {
+ derOut = new DerOutputStream();
+ derOut.putUnalignedBitString(onlySomeReasons);
+ ANY raw = new ANY(derOut.toByteArray());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ raw.encodeWithAlternateTag(Tag.get(3), bos);
+ ANY reasonEncoding = new ANY(bos.toByteArray());
+ seq.addElement(reasonEncoding);
+ }
+
+ if (indirectCRL != false) {
+ seq.addElement(Tag.get(4), new BOOLEAN(true));
+ }
+
+ seq.encode(implicitTag, ostream);
+
+ } catch (InvalidBERException e) {
+ // this shouldn't happen unless there is a bug in one of
+ // the Sun encoding classes
+ throw new IOException(e.toString());
+ }
+ }
+
+ public static void main(String args[]) {
+
+ try {
+ if (args.length != 1) {
+ System.out.println("Usage: IssuingDistributionPoint <outfile>");
+ System.exit(-1);
+ }
+
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(args[0]));
+
+ SEQUENCE idps = new SEQUENCE();
+
+ IssuingDistributionPoint idp = new IssuingDistributionPoint();
+
+ X500Name dn = new X500Name("CN=Skovw Wjasldk,E=nicolson@netscape.com" +
+ ",OU=Certificate Server,O=Netscape,C=US");
+ GeneralNames generalNames = new GeneralNames();
+ generalNames.addElement(dn);
+ idp.setFullName(generalNames);
+ idps.addElement(idp);
+
+ idp = new IssuingDistributionPoint();
+ URIName uri = new URIName("http://www.mycrl.com/go/here");
+ generalNames = new GeneralNames();
+ generalNames.addElement(uri);
+ idp.setFullName(generalNames);
+ idp.setOnlyContainsUserCerts(true);
+ idp.setOnlyContainsCACerts(true);
+ idp.setIndirectCRL(true);
+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 });
+ idp.setOnlySomeReasons(ba);
+ idps.addElement(idp);
+
+ idps.encode(bos);
+ bos.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/IssuingDistributionPointExtension.java b/base/util/src/netscape/security/x509/IssuingDistributionPointExtension.java
new file mode 100644
index 000000000..d5f5100bf
--- /dev/null
+++ b/base/util/src/netscape/security/x509/IssuingDistributionPointExtension.java
@@ -0,0 +1,416 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.CertificateException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+import org.mozilla.jss.asn1.ASN1Util;
+
+/**
+ * A critical CRL extension that identifies the CRL distribution point
+ * for a particular CRL
+ *
+ * <pre>
+ * issuingDistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
+ * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
+ * onlySomeReasons [3] ReasonFlags OPTIONAL,
+ * indirectCRL [4] BOOLEAN DEFAULT FALSE }
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6) }
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ *
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * </pre>
+ */
+public class IssuingDistributionPointExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1281544042375527550L;
+
+ /**
+ * The Object Identifier for this extension.
+ */
+ public static final String OID = "2.5.29.28";
+
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "IssuingDistributionPoint";
+ public static final String ISSUING_DISTRIBUTION_POINT = "issuing_distribution_point";
+
+ // Private data members
+ private IssuingDistributionPoint issuingDistributionPoint = null;
+
+ // Cached DER-encoding to improve performance.
+ private byte[] cachedEncoding = null;
+
+ static {
+ try {
+ OIDMap.addAttribute(IssuingDistributionPointExtension.class.getName(),
+ OID, NAME);
+ } catch (CertificateException e) {
+ }
+ }
+
+ /**
+ * This constructor is very important, since it will be called
+ * by the system.
+ */
+ public IssuingDistributionPointExtension(Boolean critical, Object value)
+ throws IOException {
+
+ this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
+ this.critical = critical.booleanValue();
+ this.extensionValue = (byte[]) ((byte[]) value).clone();
+
+ byte[] extValue = this.extensionValue;
+ issuingDistributionPoint = new IssuingDistributionPoint();
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint");
+ }
+
+ while (val.data.available() != 0) {
+ DerValue opt = val.data.getDerValue();
+
+ if (opt != null) {
+ for (int i = 0; i < 5; i++) {
+ if (opt.isContextSpecific((byte) i)) {
+ if ((i == 0 && opt.isConstructed() && opt.data.available() != 0) ||
+ (i != 0 && (!opt.isConstructed()) && opt.data.available() != 0)) {
+
+ if (i == 0) {
+ DerValue opt1 = opt.data.getDerValue();
+ if (opt1 != null) {
+ if (opt1.isContextSpecific((byte) 0)) {
+ if (opt1.isConstructed() && opt1.data.available() != 0) {
+ opt1.resetTag(DerValue.tag_Sequence);
+
+ try {
+ GeneralNames fullName = new GeneralNames(opt1);
+ if (fullName != null) {
+ issuingDistributionPoint.setFullName(fullName);
+ }
+ } catch (GeneralNamesException e) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint "
+ + e);
+ } catch (IOException e) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint "
+ + e);
+ }
+ } else {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint");
+ }
+
+ } else if (opt1.isContextSpecific((byte) 1)) {
+ if (opt1.isConstructed() && opt1.data.available() != 0) {
+ opt1.resetTag(DerValue.tag_Set);
+
+ try {
+ RDN relativeName = new RDN(opt1);
+ if (relativeName != null) {
+ issuingDistributionPoint.setRelativeName(relativeName);
+ }
+ } catch (IOException e) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint "
+ + e);
+ }
+ } else {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint");
+ }
+ }
+ }
+
+ } else if (i == 3) {
+ opt.resetTag(DerValue.tag_BitString);
+ try {
+ BitArray reasons = opt.getUnalignedBitString();
+ issuingDistributionPoint.setOnlySomeReasons(reasons);
+
+ @SuppressWarnings("unused")
+ byte[] a = reasons.toByteArray(); // check for errors
+ } catch (IOException e) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e);
+ }
+
+ } else {
+ opt.resetTag(DerValue.tag_Boolean);
+ try {
+ boolean b = opt.getBoolean();
+ if (i == 1) {
+ issuingDistributionPoint.setOnlyContainsUserCerts(b);
+ } else if (i == 2) {
+ issuingDistributionPoint.setOnlyContainsCACerts(b);
+ } else if (i == 4) {
+ issuingDistributionPoint.setIndirectCRL(b);
+ }
+ } catch (IOException e) {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e);
+ }
+ }
+ } else {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint");
+ }
+ }
+ }
+ } else {
+ throw new IOException("Invalid encoding of IssuingDistributionPoint");
+ }
+ }
+
+ }
+
+ /**
+ * Creates a new IssuingDistributionPoint extension, with the given
+ * issuing distribution point as the first element.
+ */
+ public IssuingDistributionPointExtension(IssuingDistributionPoint idp) {
+ this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
+ this.critical = true;
+ issuingDistributionPoint = idp;
+ }
+
+ /**
+ * Returns the issuing distribution point.
+ */
+ public IssuingDistributionPoint getIssuingDistributionPoint() {
+ return issuingDistributionPoint;
+ }
+
+ /**
+ * Sets the criticality of this extension. PKIX dictates that this
+ * extension SHOULD be critical, so applications can make it not critical
+ * if they have a very good reason. By default, the extension is critical.
+ */
+ public void setCritical(boolean critical) {
+ this.critical = critical;
+ }
+
+ /**
+ * Gets the criticality of this extension. PKIX dictates that this
+ * extension SHOULD be critical, so by default, the extension is critical.
+ */
+ public boolean getCritical(boolean critical) {
+ return this.critical;
+ }
+
+ /**
+ * Encodes this extension to the given DerOutputStream.
+ * This method re-encodes each time it is called, so it is not very
+ * efficient.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ extensionValue = ASN1Util.encode(issuingDistributionPoint);
+ super.encode(out);
+ }
+
+ /**
+ * Should be called if any change is made to this data structure
+ * so that the cached DER encoding can be discarded.
+ */
+ public void flushCachedEncoding() {
+ cachedEncoding = null;
+ }
+
+ /**
+ * Returns a printable representation of the IssuingDistributionPointExtension
+ */
+
+ public String toString() {
+ return NAME;
+ }
+
+ /**
+ * DER-encodes this extension to the given OutputStream.
+ */
+ public void encode(OutputStream ostream)
+ throws CertificateException, IOException {
+ if (cachedEncoding == null) {
+ // only re-encode if necessary
+ DerOutputStream tmp = new DerOutputStream();
+ encode(tmp);
+ cachedEncoding = tmp.toByteArray();
+ }
+ ostream.write(cachedEncoding);
+ }
+
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ throw new IOException("Not supported");
+ }
+
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
+ if (!(obj instanceof IssuingDistributionPoint)) {
+ throw new IOException("Attribute value should be of type IssuingDistributionPoint.");
+ }
+ issuingDistributionPoint = (IssuingDistributionPoint) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuingDistributionPointExtension");
+ }
+ }
+
+ public Object get(String name)
+ throws CertificateException, IOException {
+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
+ return issuingDistributionPoint;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuingDistributionPointExtension");
+ }
+ }
+
+ public void delete(String name)
+ throws CertificateException, IOException {
+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
+ issuingDistributionPoint = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:IssuingDistributionPointExtension");
+ }
+ }
+
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(ISSUING_DISTRIBUTION_POINT);
+ return (elements.elements());
+ // return (new Vector()).elements();
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Test driver.
+ */
+ public static void main(String args[]) {
+
+ try {
+
+ if (args.length != 1) {
+ System.out.println("Usage: IssuingDistributionPointExtension " +
+ "<outfile>");
+ System.exit(-1);
+ }
+
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(args[0]));
+
+ // URI only
+ IssuingDistributionPoint idp = new IssuingDistributionPoint();
+ URIName uri = new URIName("http://www.mycrl.com/go/here");
+ GeneralNames generalNames = new GeneralNames();
+ generalNames.addElement(uri);
+ idp.setFullName(generalNames);
+ IssuingDistributionPointExtension idpExt =
+ new IssuingDistributionPointExtension(idp);
+
+ // DN only
+ idp = new IssuingDistributionPoint();
+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" +
+ ",OU=Certificate Server,O=Fedora,C=US");
+ generalNames = new GeneralNames();
+ generalNames.addElement(dn);
+ idp.setFullName(generalNames);
+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp);
+
+ // DN + reason
+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 });
+ idp = new IssuingDistributionPoint();
+ idp.setFullName(generalNames);
+ idp.setOnlySomeReasons(ba);
+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp);
+
+ // relative DN + reason + crlIssuer
+ idp = new IssuingDistributionPoint();
+ RDN rdn = new RDN("OU=foobar dept");
+ idp.setRelativeName(rdn);
+ idp.setOnlySomeReasons(ba);
+ idp.setOnlyContainsCACerts(true);
+ idp.setOnlyContainsUserCerts(true);
+ idp.setIndirectCRL(true);
+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp);
+
+ idpExt.setCritical(false);
+ idpExt.encode(bos);
+
+ bos.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/KeyIdentifier.java b/base/util/src/netscape/security/x509/KeyIdentifier.java
new file mode 100644
index 000000000..631f6fd65
--- /dev/null
+++ b/base/util/src/netscape/security/x509/KeyIdentifier.java
@@ -0,0 +1,87 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Key Identifier ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class KeyIdentifier implements java.io.Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2412286879441154979L;
+ private byte[] octetString;
+
+ /**
+ * Create a KeyIdentifier with the passed bit settings.
+ *
+ * @param octetString the octet string identifying the key identifier.
+ */
+ public KeyIdentifier(byte[] octetString) {
+ this.octetString = octetString;
+ }
+
+ /**
+ * Create a KeyIdentifier from the DER encoded value.
+ *
+ * @param val the DerValue
+ */
+ public KeyIdentifier(DerValue val) throws IOException {
+ octetString = val.getOctetString();
+ }
+
+ /**
+ * Return the value of the KeyIdentifier as byte array.
+ */
+ public byte[] getIdentifier() {
+ return ((byte[]) octetString.clone());
+ }
+
+ /**
+ * Returns a printable representation of the KeyUsage.
+ */
+ public String toString() {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String octetbits = pp.toHexString(octetString);
+
+ String s = "KeyIdentifier [\n";
+ s += octetbits;
+ s += "]\n";
+ return (s);
+ }
+
+ /**
+ * Write the KeyIdentifier to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException
+ */
+ void encode(DerOutputStream out) throws IOException {
+ out.putOctetString(octetString);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/KeyUsageExtension.java b/base/util/src/netscape/security/x509/KeyUsageExtension.java
new file mode 100644
index 000000000..56084dbcf
--- /dev/null
+++ b/base/util/src/netscape/security/x509/KeyUsageExtension.java
@@ -0,0 +1,414 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Key Usage Extension.
+ *
+ * <p>
+ * This extension, if present, defines the purpose (e.g., encipherment, signature, certificate signing) of the key
+ * contained in the certificate. The usage restriction might be employed when a multipurpose key is to be restricted
+ * (e.g., when an RSA key should be used only for signing or only for key encipherment).
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class KeyUsageExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2899719374157256708L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.KeyUsage";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "KeyUsage";
+ public static final String DIGITAL_SIGNATURE = "digital_signature";
+ public static final String NON_REPUDIATION = "non_repudiation";
+ public static final String KEY_ENCIPHERMENT = "key_encipherment";
+ public static final String DATA_ENCIPHERMENT = "data_encipherment";
+ public static final String KEY_AGREEMENT = "key_agreement";
+ public static final String KEY_CERTSIGN = "key_certsign";
+ public static final String CRL_SIGN = "crl_sign";
+ public static final String ENCIPHER_ONLY = "encipher_only";
+ public static final String DECIPHER_ONLY = "decipher_only";
+
+ public static final int DIGITAL_SIGNATURE_BIT = 0;
+ public static final int NON_REPUDIATION_BIT = 1;
+ public static final int KEY_ENCIPHERMENT_BIT = 2;
+ public static final int DATA_ENCIPHERMENT_BIT = 3;
+ public static final int KEY_AGREEMENT_BIT = 4;
+ public static final int KEY_CERTSIGN_BIT = 5;
+ public static final int CRL_SIGN_BIT = 6;
+ public static final int ENCIPHER_ONLY_BIT = 7;
+ public static final int DECIPHER_ONLY_BIT = 8;
+
+ public static final int NBITS = 9;
+
+ public static String[] names = new String[NBITS];
+
+ static {
+ names[DIGITAL_SIGNATURE_BIT] = DIGITAL_SIGNATURE;
+ names[NON_REPUDIATION_BIT] = NON_REPUDIATION;
+ names[KEY_ENCIPHERMENT_BIT] = KEY_ENCIPHERMENT;
+ names[DATA_ENCIPHERMENT_BIT] = DATA_ENCIPHERMENT;
+ names[KEY_AGREEMENT_BIT] = KEY_AGREEMENT;
+ names[KEY_CERTSIGN_BIT] = KEY_CERTSIGN;
+ names[CRL_SIGN_BIT] = CRL_SIGN;
+ names[ENCIPHER_ONLY_BIT] = ENCIPHER_ONLY;
+ names[DECIPHER_ONLY_BIT] = DECIPHER_ONLY;
+ }
+
+ // Private data members
+ private boolean[] bitString;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ os.putUnalignedBitString(this.bitString);
+ this.extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Check if bit is set.
+ *
+ * @param position the position in the bit string to check.
+ */
+ private boolean isSet(int position) {
+ if (bitString.length <= position)
+ return false;
+ return bitString[position];
+ }
+
+ /**
+ * Set the bit at the specified position.
+ */
+ private void set(int position, boolean val) {
+ // enlarge bitString if necessary
+ if (position >= bitString.length) {
+ boolean[] tmp = new boolean[position + 1];
+ System.arraycopy(bitString, 0, tmp, 0, bitString.length);
+ bitString = tmp;
+ }
+ bitString[position] = val;
+ }
+
+ /**
+ * Create a KeyUsageExtension with the passed bit settings. The criticality
+ * is set to true.
+ *
+ * @param bitString the bits to be set for the extension.
+ */
+ public KeyUsageExtension(boolean critical, byte[] bitString) throws IOException {
+ this.bitString =
+ new BitArray(bitString.length * 8, bitString).toBooleanArray();
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ public KeyUsageExtension(byte[] bitString) throws IOException {
+ this.bitString =
+ new BitArray(bitString.length * 8, bitString).toBooleanArray();
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create a KeyUsageExtension with the passed bit settings. The criticality
+ * is set to true.
+ *
+ * @param bitString the bits to be set for the extension.
+ */
+ public KeyUsageExtension(boolean critical, boolean[] bitString) throws IOException {
+ this.bitString = bitString;
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ public KeyUsageExtension(boolean[] bitString) throws IOException {
+ this.bitString = bitString;
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create a KeyUsageExtension with the passed bit settings. The criticality
+ * is set to true.
+ *
+ * @param bitString the bits to be set for the extension.
+ */
+ public KeyUsageExtension(BitArray bitString) throws IOException {
+ this.bitString = bitString.toBooleanArray();
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = true;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value of the same.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public KeyUsageExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = critical.booleanValue();
+ /*
+ * The following check should be activated again after
+ * the PKIX profiling work becomes standard and the check
+ * is not a barrier to interoperability !
+ * if (!this.critical) {
+ * throw new IOException("KeyUsageExtension not marked critical,"
+ * + " invalid profile.");
+ * }
+ */
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ this.bitString = val.getUnalignedBitString().toBooleanArray();
+ }
+
+ /**
+ * Create a default key usage.
+ */
+ public KeyUsageExtension() {
+ extensionId = PKIXExtensions.KeyUsage_Id;
+ critical = true;
+ bitString = new boolean[0];
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (!(obj instanceof Boolean)) {
+ throw new IOException("Attribute must be of type Boolean.");
+ }
+ boolean val = ((Boolean) obj).booleanValue();
+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
+ set(0, val);
+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
+ set(1, val);
+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
+ set(2, val);
+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
+ set(3, val);
+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
+ set(4, val);
+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
+ set(5, val);
+ } else if (name.equalsIgnoreCase(CRL_SIGN)) {
+ set(6, val);
+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
+ set(7, val);
+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
+ set(8, val);
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:KeyUsage.");
+ }
+ encodeThis();
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
+ return new Boolean(isSet(0));
+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
+ return new Boolean(isSet(1));
+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
+ return new Boolean(isSet(2));
+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
+ return new Boolean(isSet(3));
+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
+ return new Boolean(isSet(4));
+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
+ return new Boolean(isSet(5));
+ } else if (name.equalsIgnoreCase(CRL_SIGN)) {
+ return new Boolean(isSet(6));
+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
+ return new Boolean(isSet(7));
+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
+ return new Boolean(isSet(8));
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:KeyUsage.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
+ set(0, false);
+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
+ set(1, false);
+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
+ set(2, false);
+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
+ set(3, false);
+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
+ set(4, false);
+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
+ set(5, false);
+ } else if (name.equalsIgnoreCase(CRL_SIGN)) {
+ set(6, false);
+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
+ set(7, false);
+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
+ set(8, false);
+ } else {
+ throw new IOException("Attribute name not recognized by"
+ + " CertAttrSet:KeyUsage.");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the KeyUsage.
+ */
+ public String toString() {
+ String s = super.toString() + "KeyUsage [\n";
+
+ try {
+ if (isSet(0)) {
+ s += " DigitalSignature\n";
+ }
+ if (isSet(1)) {
+ s += " Non_repudiation\n";
+ }
+ if (isSet(2)) {
+ s += " Key_Encipherment\n";
+ }
+ if (isSet(3)) {
+ s += " Data_Encipherment\n";
+ }
+ if (isSet(4)) {
+ s += " Key_Agreement\n";
+ }
+ if (isSet(5)) {
+ s += " Key_CertSign\n";
+ }
+ if (isSet(6)) {
+ s += " Crl_Sign\n";
+ }
+ if (isSet(7)) {
+ s += " Encipher_Only\n";
+ }
+ if (isSet(8)) {
+ s += " Decipher_Only\n";
+ }
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ }
+
+ s += "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.KeyUsage_Id;
+ this.critical = true;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(DIGITAL_SIGNATURE);
+ elements.addElement(NON_REPUDIATION);
+ elements.addElement(KEY_ENCIPHERMENT);
+ elements.addElement(DATA_ENCIPHERMENT);
+ elements.addElement(KEY_AGREEMENT);
+ elements.addElement(KEY_CERTSIGN);
+ elements.addElement(CRL_SIGN);
+ elements.addElement(ENCIPHER_ONLY);
+ elements.addElement(DECIPHER_ONLY);
+
+ return (elements.elements());
+ }
+
+ public boolean[] getBits() {
+ return (boolean[]) bitString.clone();
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/LdapDNStrConverter.java b/base/util/src/netscape/security/x509/LdapDNStrConverter.java
new file mode 100644
index 000000000..a8cb87813
--- /dev/null
+++ b/base/util/src/netscape/security/x509/LdapDNStrConverter.java
@@ -0,0 +1,144 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+/**
+ * Abstract class that converts a Ldap DN String to an X500Name, RDN or AVA
+ * and vice versa, except the string is a java string in unicode.
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public abstract class LdapDNStrConverter {
+ //
+ // public parsing methods.
+ //
+
+ /**
+ * Converts a Ldap DN string to a X500Name object.
+ *
+ * @param dn a Ldap DN String.
+ *
+ * @return an X500Name object for the Ldap DN String.
+ */
+ public abstract X500Name parseDN(String dn)
+ throws IOException;
+
+ /**
+ * Like parseDN with a specified DER encoding order for Directory Strings.
+ */
+ public abstract X500Name parseDN(String dn, byte[] tags)
+ throws IOException;
+
+ /**
+ * Converts a Ldap DN string to a RDN object.
+ *
+ * @param rdn a Ldap DN String
+ *
+ * @return an RDN object.
+ */
+ public abstract RDN parseRDN(String rdn)
+ throws IOException;
+
+ /**
+ * Like parseRDN with a specified DER encoding order for Directory Strings.
+ */
+ public abstract RDN parseRDN(String rdn, byte[] tags)
+ throws IOException;
+
+ /**
+ * Converts a Ldap DN string to a AVA object.
+ *
+ * @param ava a Ldap DN string.
+ * @return an AVA object.
+ */
+ public abstract AVA parseAVA(String ava)
+ throws IOException;
+
+ /**
+ * Like parseAVA with a specified DER encoding order for Directory Strings.
+ */
+ public abstract AVA parseAVA(String rdn, byte[] tags)
+ throws IOException;
+
+ //
+ // public encoding methods.
+ //
+
+ /**
+ * Converts a X500Name object to a Ldap dn string.
+ *
+ * @param dn an X500Name object.
+ * @return a Ldap DN String.
+ */
+ public abstract String encodeDN(X500Name dn) throws IOException;
+
+ /**
+ * Converts an RDN object to a Ldap dn string.
+ *
+ * @param rdn an RDN object.
+ * @return a Ldap dn string.
+ */
+ public abstract String encodeRDN(RDN rdn) throws IOException;
+
+ /**
+ * Converts an AVA object to a Ldap dn string.
+ *
+ * @param ava An AVA object.
+ * @return A Ldap dn string.
+ */
+ public abstract String encodeAVA(AVA ava) throws IOException;
+
+ //
+ // public static methods
+ //
+
+ /**
+ * Gets a global default Ldap DN String converter.
+ * Currently it is LdapV3DNStrConverter object using the default
+ * X500NameAttrMap and accepts unknown OIDs.
+ *
+ * @see netscape.security.x509.LdapV3DNStrConverter
+ *
+ * @return The global default LdapDNStrConverter instance.
+ */
+ public static LdapDNStrConverter getDefault() {
+ return defaultConverter;
+ }
+
+ /**
+ * Set the global default LdapDNStrConverter object.
+ *
+ * @param defConverter A LdapDNStrConverter object to become
+ * the global default.
+ */
+ public static void setDefault(LdapDNStrConverter defConverter) {
+ if (defConverter == null)
+ throw new IllegalArgumentException(
+ "The default Ldap DN String converter cannot be set to null.");
+ defaultConverter = defConverter;
+ }
+
+ //
+ // private static variables
+ //
+
+ private static LdapDNStrConverter defaultConverter = new LdapV3DNStrConverter();
+}
diff --git a/base/util/src/netscape/security/x509/LdapV3DNStrConverter.java b/base/util/src/netscape/security/x509/LdapV3DNStrConverter.java
new file mode 100644
index 000000000..1245cc6bd
--- /dev/null
+++ b/base/util/src/netscape/security/x509/LdapV3DNStrConverter.java
@@ -0,0 +1,824 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Arrays;
+import java.util.Vector;
+
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * A converter that converts Ldap v3 DN strings as specified in
+ * draft-ietf-asid-ldapv3-dn-03.txt to a X500Name, RDN or AVA and
+ * vice versa.
+ *
+ * @see LdapDNStrConverter
+ * @see X500Name
+ * @see RDN
+ * @see AVA
+ * @see X500NameAttrMap
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public class LdapV3DNStrConverter extends LdapDNStrConverter {
+ //
+ // Constructors
+ //
+
+ /**
+ * Constructs a LdapV3DNStrConverter using the global default
+ * X500NameAttrMap and accept OIDs not in the default X500NameAttrMap.
+ *
+ * @see X500NameAttrMap
+ */
+ public LdapV3DNStrConverter() {
+ attrMap = X500NameAttrMap.getDefault();
+
+ acceptUnknownOids = true;
+ }
+
+ /**
+ * Constructs a LdapV3DNStrConverter using the specified X500NameAttrMap
+ * and a boolean indicating whether to accept OIDs not listed in the
+ * X500NameAttrMap.
+ *
+ * @param attributeMap a X500NameAttrMap
+ * @param doAcceptUnknownOids whether to convert unregistered OIDs
+ * (oids not in the X500NameAttrMap)
+ * @see X500NameAttrMap
+ */
+ public LdapV3DNStrConverter(X500NameAttrMap attributeMap,
+ boolean doAcceptUnknownOids) {
+ attrMap = attributeMap;
+ acceptUnknownOids = doAcceptUnknownOids;
+
+ }
+
+ //
+ // public parsing methods
+ // From LdapDNStrConverter interface
+ //
+
+ /**
+ * Parse a Ldap v3 DN string to a X500Name.
+ *
+ * @param dn a LDAP v3 DN String
+ * @return a X500Name
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public X500Name parseDN(String dn)
+ throws IOException {
+ return parseDN(dn, null);
+ }
+
+ /**
+ * Like parseDN(String) with a DER encoding order given as argument for
+ * Directory Strings.
+ */
+ public X500Name parseDN(String dn, byte[] encodingOrder)
+ throws IOException {
+ StringReader dn_reader = new StringReader(dn);
+ PushbackReader in = new PushbackReader(dn_reader, 5);
+
+ return parseDN(in, encodingOrder);
+ }
+
+ /**
+ * Parse a Ldap v3 DN string with a RDN component to a RDN
+ *
+ * @param rdn a LDAP v3 DN String
+ * @return a RDN
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public RDN parseRDN(String rdn)
+ throws IOException {
+ return parseRDN(rdn, null);
+ }
+
+ /**
+ * Like parseRDN(String) with a DER encoding order given as argument for
+ * Directory Strings.
+ */
+ public RDN parseRDN(String rdn, byte[] encodingOrder)
+ throws IOException {
+ StringReader rdn_reader = new StringReader(rdn);
+ PushbackReader in = new PushbackReader(rdn_reader, 5);
+
+ return parseRDN(in, null);
+ }
+
+ /**
+ * Parse a Ldap v3 DN string with a AVA component to a AVA.
+ *
+ * @param ava a LDAP v3 DN string
+ * @return a AVA
+ */
+ public AVA parseAVA(String ava)
+ throws IOException {
+ return parseAVA(ava, null);
+ }
+
+ /**
+ * Like parseDN(String) with a DER encoding order given as argument for
+ * Directory Strings.
+ */
+ public AVA parseAVA(String ava, byte[] encodingOrder)
+ throws IOException {
+ StringReader ava_reader = new StringReader(ava);
+ PushbackReader in = new PushbackReader(ava_reader, 5);
+
+ return parseAVA(in, encodingOrder);
+ }
+
+ //
+ // public parsing methods called by other methods.
+ //
+
+ /**
+ * Parses a Ldap DN string in a string reader to a X500Name.
+ *
+ * @param in Pushback string reader for a Ldap DN string.
+ * The pushback reader must have a pushback buffer size > 2.
+ *
+ * @return a X500Name
+ *
+ * @exception IOException if any reading or parsing error occurs.
+ */
+ public X500Name parseDN(PushbackReader in)
+ throws IOException {
+ return parseDN(in, null);
+ }
+
+ /**
+ * Like parseDN(PushbackReader in) with a DER encoding order given as
+ * argument for Directory Strings.
+ */
+ public X500Name parseDN(PushbackReader in, byte[] encodingOrder)
+ throws IOException {
+ RDN rdn;
+ int lastChar;
+ Vector<RDN> rdnVector = new Vector<RDN>();
+ RDN names[];
+ int i, j;
+
+ do {
+ rdn = parseRDN(in, encodingOrder);
+ rdnVector.addElement(rdn);
+ lastChar = in.read();
+ } while (lastChar == ',' || lastChar == ';');
+
+ names = new RDN[rdnVector.size()];
+ for (i = 0, j = rdnVector.size() - 1; i < rdnVector.size(); i++, j--)
+ names[j] = (RDN) rdnVector.elementAt(i);
+ return new X500Name(names);
+ }
+
+ /**
+ * Parses Ldap DN string with a rdn component
+ * from a string reader to a RDN. The string reader will point
+ * to the separator after the rdn component or -1 if at end of string.
+ *
+ * @param in Pushback string reader containing a Ldap DN string with
+ * at least one rdn component.
+ * The pushback reader must have a pushback buffer size > 2.
+ *
+ * @return RDN object of the first rdn component in the Ldap DN string.
+ *
+ * @exception IOException if any read or parse error occurs.
+ */
+ public RDN parseRDN(PushbackReader in)
+ throws IOException {
+ return parseRDN(in, null);
+ }
+
+ /**
+ * Like parseRDN(PushbackReader) with a DER encoding order given as
+ * argument for Directory Strings.
+ */
+ public RDN parseRDN(PushbackReader in, byte[] encodingOrder)
+ throws IOException {
+ Vector<AVA> avaVector = new Vector<AVA>();
+ AVA ava;
+ int lastChar;
+ AVA assertion[];
+
+ do {
+ ava = parseAVA(in, encodingOrder);
+ avaVector.addElement(ava);
+ lastChar = in.read();
+ } while (lastChar == '+');
+
+ if (lastChar != -1)
+ in.unread(lastChar);
+
+ assertion = new AVA[avaVector.size()];
+ for (int i = 0; i < avaVector.size(); i++)
+ assertion[i] = (AVA) avaVector.elementAt(i);
+ return new RDN(assertion);
+ }
+
+ /**
+ * Parses a Ldap DN string with a AVA component
+ * from a string reader to an AVA. The string reader will point
+ * to the AVA separator after the ava string or -1 if end of string.
+ *
+ * @param in a Pushback reader containg a Ldap string with
+ * at least one AVA component.
+ * The Pushback reader must have a pushback buffer size > 2.
+ *
+ * @return AVA object of the first AVA component in the Ldap DN string.
+ */
+ public AVA parseAVA(PushbackReader in)
+ throws IOException {
+ return parseAVA(in, null);
+ }
+
+ /**
+ * Like parseAVA(PushbackReader) with a DER encoding order given as
+ * argument for Directory Strings.
+ */
+ public AVA parseAVA(PushbackReader in, byte[] encodingOrder)
+ throws IOException {
+ int c;
+ ObjectIdentifier oid;
+ DerValue value;
+ StringBuffer keywordBuf;
+ StringBuffer valueBuf;
+ ByteArrayOutputStream berStream;
+ char hexChar1, hexChar2;
+ CharArrayWriter hexCharsBuf;
+ String endChars;
+
+ /* First get the keyword indicating the attribute's type,
+ * and map it to the appropriate OID.
+ */
+ keywordBuf = new StringBuffer();
+ for (;;) {
+ c = in.read();
+ if (c == '=')
+ break;
+ if (c == -1) {
+ throw new IOException("Bad AVA format: Missing '='");
+ }
+ keywordBuf.append((char) c);
+ }
+ oid = parseAVAKeyword(keywordBuf.toString());
+
+ /* Now parse the value. "#hex", a quoted string, or a string
+ * terminated by "+", ",", ";", ">". Whitespace before or after
+ * the value is stripped.
+ */
+ for (c = in.read(); c == ' '; c = in.read())
+ continue;
+ if (c == -1)
+ throw new IOException("Bad AVA format: Missing attribute value");
+
+ if (c == '#') {
+ /*
+ * NOTE per LDAPv3 dn string ietf standard the value represented
+ * by this form is a BER value. But we only support DER value here
+ * which is only a form of BER.
+ */
+ berStream = new ByteArrayOutputStream();
+ int b;
+ for (;;) {
+ hexChar1 = (char) (c = in.read());
+ if (c == -1 || octoEndChars.indexOf(c) > 0) // end of value
+ break;
+ hexChar2 = (char) (c = in.read());
+ if (hexDigits.indexOf(hexChar1) == -1 ||
+ hexDigits.indexOf(hexChar2) == -1)
+ throw new IOException("Bad AVA value: bad hex value.");
+ b = (Character.digit(hexChar1, 16) << 4) +
+ Character.digit(hexChar2, 16);
+ berStream.write(b);
+ }
+ if (berStream.size() == 0)
+ throw new IOException("bad AVA format: invalid hex value");
+
+ value = parseAVAValue(berStream.toByteArray(), oid);
+
+ while (c == ' ' && c != -1)
+ c = in.read();
+ } else {
+ valueBuf = new StringBuffer();
+ boolean quoted = false;
+ if (c == '"') {
+ quoted = true;
+ endChars = quotedEndChars;
+ if ((c = in.read()) == -1)
+ throw new IOException("Bad AVA format: Missing attrValue");
+ } else {
+ endChars = valueEndChars;
+ }
+
+ // QUOTATION * ( quotechar / pair ) QUOTATION
+ // quotechar = any character except '\' or QUOTATION
+ // pair = '\' ( special | '\' | QUOTATION | hexpair )
+ while (c != -1 && endChars.indexOf(c) == -1) {
+ if (c == '\\') {
+ if ((c = in.read()) == -1)
+ throw new IOException("Bad AVA format: expecting " +
+ "escaped char.");
+ // expect escaping of special chars, space and CR.
+ if (specialChars.indexOf((char) c) != -1 || c == '\n' ||
+ c == '\\' || c == '"' || c == ' ') {
+ valueBuf.append((char) c);
+ } else if (hexDigits.indexOf(c) != -1) {
+ hexCharsBuf = new CharArrayWriter();
+ // handle sequence of '\' hexpair
+ do {
+ hexChar1 = (char) c;
+ hexChar2 = (char) (c = in.read());
+ if (hexDigits.indexOf((char) c) == -1)
+ throw new IOException("Bad AVA format: " +
+ "invalid escaped hex pair");
+ hexCharsBuf.write(hexChar1);
+ hexCharsBuf.write(hexChar2);
+ // read ahead to next '\' hex-char if any.
+ if ((c = in.read()) == -1)
+ break;
+ if (c != '\\') {
+ in.unread(c);
+ break;
+ }
+ if ((c = in.read()) == -1)
+ throw new IOException("Bad AVA format: " +
+ "expecting escaped char.");
+ if (hexDigits.indexOf((char) c) == -1) {
+ in.unread(c);
+ in.unread((int) '\\');
+ break;
+ }
+ } while (true);
+ valueBuf.append(
+ getStringFromHexpairs(hexCharsBuf.toCharArray()));
+ } else {
+ throw new IOException("Bad AVA format: " +
+ "invalid escaping");
+ }
+ } else
+ valueBuf.append((char) c);
+ c = in.read();
+ }
+
+ value = parseAVAValue(
+ valueBuf.toString().trim(), oid, encodingOrder);
+
+ if (quoted) { // move to next non-white space
+ do {
+ c = in.read();
+ } while (c == ' ');
+ if (c != -1 && valueEndChars.indexOf(c) == -1)
+ throw new IOException(
+ "Bad AVA format: separator expected at end of ava.");
+ }
+ }
+
+ if (c != -1)
+ in.unread(c);
+
+ return new AVA(oid, value);
+ }
+
+ /**
+ * Converts a AVA keyword from a Ldap DN string to an ObjectIdentifier
+ * from the attribute map or, if this keyword is an OID not
+ * in the attribute map, create a new ObjectIdentifier for the keyword
+ * if acceptUnknownOids is true.
+ *
+ * @param avaKeyword AVA keyword from a Ldap DN string.
+ *
+ * @return a ObjectIdentifier object
+ * @exception IOException if the keyword is an OID not in the attribute
+ * map and acceptUnknownOids is false, or
+ * if an error occurs during conversion.
+ */
+ public ObjectIdentifier parseAVAKeyword(String avaKeyword)
+ throws IOException {
+ String keyword = avaKeyword.toUpperCase().trim();
+ String oid_str = null;
+ ObjectIdentifier oid, new_oid;
+
+ if (Character.digit(keyword.charAt(0), 10) != -1) {
+ // value is an oid string of 1.2.3.4
+ oid_str = keyword;
+ } else if (keyword.startsWith("oid.") || keyword.startsWith("OID.")) {
+ // value is an oid string of oid.1.2.3.4 or OID.1.2...
+ oid_str = keyword.substring(4);
+ }
+
+ if (oid_str != null) {
+ // value is an oid string of 1.2.3.4 or oid.1.2.3.4 or OID.1.2...
+ new_oid = new ObjectIdentifier(oid_str);
+ oid = attrMap.getOid(new_oid);
+ if (oid == null) {
+ if (!acceptUnknownOids)
+ throw new IOException("Unknown AVA OID.");
+ oid = new_oid;
+ }
+ } else {
+ oid = attrMap.getOid(keyword);
+ if (oid == null)
+ throw new IOException("Unknown AVA keyword '" + keyword + "'.");
+ }
+
+ return oid;
+ }
+
+ /**
+ * Converts a AVA value from a Ldap dn string to a
+ * DerValue according the attribute type. For example, a value for
+ * CN, OU or O is expected to be a Directory String and will be converted
+ * to a DerValue of ASN.1 type PrintableString, T61String or
+ * UniversalString. A Directory String is a ASN.1 CHOICE of Printable,
+ * T.61 or Universal string.
+ *
+ * @param avaValueString a attribute value from a Ldap DN string.
+ * @param oid OID of the attribute.
+ *
+ * @return DerValue for the value.
+ *
+ * @exception IOException if an error occurs during conversion.
+ * @see AVAValueConverter
+ */
+ public DerValue parseAVAValue(String avaValueString, ObjectIdentifier oid)
+ throws IOException {
+ return parseAVAValue(avaValueString, oid, null);
+ }
+
+ /**
+ * Like parseAVAValue(String) with a DER encoding order given as argument
+ * for Directory Strings.
+ */
+ public DerValue parseAVAValue(
+ String avaValueString, ObjectIdentifier oid, byte[] encodingOrder)
+ throws IOException {
+ AVAValueConverter valueConverter = attrMap.getValueConverter(oid);
+ if (valueConverter == null) {
+ if (!acceptUnknownOids) {
+ throw new IllegalArgumentException(
+ "Unrecognized OID for AVA value conversion");
+ } else {
+ valueConverter = new GenericValueConverter();
+ }
+ }
+ return valueConverter.getValue(avaValueString, encodingOrder);
+ }
+
+ /**
+ * Converts a value in BER encoding, for example given in octothorpe form
+ * in a Ldap v3 dn string, to a DerValue. Checks if the BER encoded value
+ * is a legal value for the attribute.
+ * <p>
+ * <strong><i>NOTE:</i></strong> only DER encoded values are supported for the BER encoded value.
+ *
+ * @param berValue a value in BER encoding
+ * @param oid ObjectIdentifier of the attribute.
+ *
+ * @return DerValue for the BER encoded value
+ * @exception IOException if an error occurs during conversion.
+ */
+ public DerValue parseAVAValue(byte[] berValue, ObjectIdentifier oid)
+ throws IOException {
+ AVAValueConverter valueConverter = attrMap.getValueConverter(oid);
+ if (valueConverter == null && !acceptUnknownOids) {
+ throw new IllegalArgumentException(
+ "Unrecognized OID for AVA value conversion");
+ } else {
+ valueConverter = new GenericValueConverter();
+ }
+ return valueConverter.getValue(berValue);
+ }
+
+ //
+ // public encoding methods.
+ //
+
+ /**
+ * Converts a X500Name object to a Ldap v3 DN string (except in unicode).
+ *
+ * @param x500name a X500Name
+ *
+ * @return a Ldap v3 DN String (except in unicode).
+ *
+ * @exception IOException if an error is encountered during conversion.
+ */
+ public String encodeDN(X500Name x500name)
+ throws IOException {
+ RDN[] rdns = x500name.getNames();
+ // String fullname = null;
+ StringBuffer fullname = new StringBuffer();
+ String s;
+ int i;
+ if (rdns.length == 0)
+ return "";
+ i = rdns.length - 1;
+ fullname.append(encodeRDN(rdns[i--]));
+ while (i >= 0) {
+ s = encodeRDN(rdns[i--]);
+ fullname.append(",");
+ fullname.append(s);
+ }
+ ;
+ return fullname.toString();
+ }
+
+ /**
+ * Converts a RDN to a Ldap v3 DN string (except in unicode).
+ *
+ * @param rdn a RDN
+ *
+ * @return a LDAP v3 DN string (except in unicode).
+ *
+ * @exception IOException if an error is encountered during conversion.
+ */
+ public String encodeRDN(RDN rdn)
+ throws IOException {
+ AVA[] avas = rdn.getAssertion();
+ // String relname = null;
+ StringBuffer relname = new StringBuffer();
+ String s;
+ int i = 0;
+
+ relname.append(encodeAVA(avas[i++]));
+ while (i < avas.length) {
+ s = encodeAVA(avas[i++]);
+ relname.append("+");
+ relname.append(s);
+ }
+ ;
+ return relname.toString();
+ }
+
+ /**
+ * Converts a AVA to a Ldap v3 DN String (except in unicode).
+ *
+ * @param ava an AVA
+ *
+ * @return a Ldap v3 DN string (except in unicode).
+ *
+ * @exception IOException If an error is encountered during exception.
+ */
+ public String encodeAVA(AVA ava)
+ throws IOException {
+ if (ava == null) {
+ return "";
+ }
+ ObjectIdentifier oid = ava.getOid();
+ DerValue value = ava.getValue();
+ String keyword, valueStr;
+
+ // get attribute name
+
+ keyword = encodeOID(oid);
+ valueStr = encodeValue(value, oid);
+
+ return keyword + "=" + valueStr;
+ }
+
+ /**
+ * Converts an OID to a attribute keyword in a Ldap v3 DN string
+ * - either a keyword if known or a string of "1.2.3.4" syntax.
+ *
+ * @param oid a ObjectIdentifier
+ *
+ * @return a keyword to use in a Ldap V3 DN string.
+ *
+ * @exception IOException if an error is encountered during conversion.
+ */
+ public String encodeOID(ObjectIdentifier oid)
+ throws IOException {
+ String keyword = attrMap.getName(oid);
+ if (keyword == null) {
+ if (acceptUnknownOids)
+ keyword = oid.toString();
+ else
+ throw new IOException("Unknown OID");
+ }
+ return keyword;
+ }
+
+ /**
+ * Converts a value as a DerValue to a string in a Ldap V3 DN String.
+ * If the value cannot be converted to a string it will be encoded in
+ * octothorpe form.
+ *
+ * @param attrValue a value as a DerValue.
+ * @param oid OID for the attribute.
+ * @return a string for the value in a LDAP v3 DN String
+ * @exception IOException if an error occurs during conversion.
+ */
+ public String encodeValue(DerValue attrValue, ObjectIdentifier oid)
+ throws IOException {
+ /*
+ * Construct the value with as little copying and garbage
+ * production as practical.
+ */
+ StringBuffer retval = new StringBuffer(30);
+ int i;
+ String temp = null;
+ AVAValueConverter valueConverter;
+
+ X500NameAttrMap lAttrMap = attrMap;
+
+ if (attrValue.tag == DerValue.tag_UTF8String) {
+ lAttrMap = X500NameAttrMap.getDirDefault();
+
+ }
+
+ valueConverter = lAttrMap.getValueConverter(oid);
+ if (valueConverter == null) {
+ if (acceptUnknownOids)
+ valueConverter = new GenericValueConverter();
+ else
+ throw new IOException(
+ "Unknown AVA type for encoding AVA value");
+ }
+
+ try {
+ temp = valueConverter.getAsString(attrValue);
+
+ if (temp == null) {
+ // convert to octothorpe form.
+ byte data[] = attrValue.toByteArray();
+
+ retval.append('#');
+ for (i = 0; i < data.length; i++) {
+ retval.append(hexDigits.charAt((data[i] >> 4) & 0x0f));
+ retval.append(hexDigits.charAt(data[i] & 0x0f));
+ }
+
+ } else {
+
+ retval.append(encodeString(temp));
+
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException("malformed AVA DER Value");
+ }
+
+ return retval.toString();
+ }
+
+ /**
+ * converts a raw value string to a string in Ldap V3 DN string format.
+ *
+ * @param valueStr a 'raw' value string.
+ * @return a attribute value string in Ldap V3 DN string format.
+ */
+ public String encodeString(String valueStr) {
+ int i, j;
+ int len;
+ StringBuffer retval = new StringBuffer();
+
+ /*
+ * generate string according to ldapv3 DN. escaping is used.
+ * Strings generated this way are acceptable by rfc1779
+ * implementations.
+ */
+ len = valueStr.length();
+
+ // get index of first space at the end of the string.
+ for (j = len - 1; j >= 0 && valueStr.charAt(j) == ' '; j--)
+ continue;
+
+ // escape spaces at the beginning of the string.
+ for (i = 0; i <= j && valueStr.charAt(i) == ' '; i++) {
+ retval.append('\\');
+ retval.append(valueStr.charAt(i));
+ }
+
+ // escape special characters in the middle of the string.
+ for (; i <= j; i++) {
+ if (valueStr.charAt(i) == '\\') {
+ retval.append('\\');
+ retval.append(valueStr.charAt(i));
+ } else if (specialChars.indexOf(valueStr.charAt(i)) != -1) {
+ retval.append('\\');
+ retval.append(valueStr.charAt(i));
+ } else if (valueStr.charAt(i) == '"') {
+ retval.append('\\');
+ retval.append(valueStr.charAt(i));
+ } else
+ retval.append(valueStr.charAt(i));
+ }
+
+ // esacape spaces at the end.
+ for (; i < valueStr.length(); i++) {
+ retval.append('\\');
+ retval.append(' ');
+ }
+
+ return retval.toString();
+ }
+
+ //
+ // public get/set methods
+ //
+
+ /**
+ * gets the X500NameAttrMap used by the converter.
+ *
+ * @return X500NameAttrMap used by this converter.
+ */
+ public X500NameAttrMap getAttrMap() {
+ return attrMap;
+ }
+
+ /**
+ * returns true if the converter accepts unregistered attributes i.e.
+ * OIDS not in the X500NameAttrMap.
+ *
+ * @return true if converter converts attributes not in the
+ * X500NameAttrMap.
+ */
+ public boolean getAcceptUnknownOids() {
+ return acceptUnknownOids;
+ }
+
+ //
+ // private and protected variables
+ //
+
+ protected X500NameAttrMap attrMap;
+ protected boolean acceptUnknownOids;
+
+ //
+ // private and protected static variables & methods.
+ //
+
+ protected static final String specialChars = ",+=<>#;";
+
+ protected static final String valueEndChars = "+,;>";
+ protected static final String quotedEndChars = "\"";
+ protected static final String octoEndChars = " " + valueEndChars;
+
+ /*
+ * Values that aren't printable strings are emitted as BER-encoded
+ * hex data.
+ */
+ protected static final String hexDigits = "0123456789ABCDEFabcdef";
+
+ /**
+ * Parse a sequence of hex pairs, each pair a UTF8 byte to a java string.
+ * For example, "4C75C48D" is "Luc", the last c with caron.
+ */
+ protected static char[] getStringFromHexpairs(char[] hexPairs) throws UnsupportedEncodingException {
+ try {
+ byte[] buffer = new byte[hexPairs.length / 2];
+
+ for (int i = 0; i < buffer.length; i++) {
+ buffer[i] = (byte)
+ ((Character.digit(hexPairs[i * 2], 16) << 4) +
+ Character.digit(hexPairs[i * 2 + 1], 16));
+ }
+
+ Charset charset = Charset.forName("UTF-8");
+ CharsetDecoder decoder = charset.newDecoder();
+
+ CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(buffer));
+
+ return Arrays.copyOfRange(charBuffer.array(),
+ charBuffer.arrayOffset(), charBuffer.arrayOffset() + charBuffer.limit());
+
+ } catch (UnsupportedCharsetException e) {
+ throw new UnsupportedEncodingException(
+ "No UTF8 byte to char converter to use for " +
+ "parsing LDAP DN String");
+
+ } catch (CharacterCodingException e) {
+ throw new IllegalArgumentException(
+ "Invalid hex pair in LDAP DN String.");
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/NSCCommentExtension.java b/base/util/src/netscape/security/x509/NSCCommentExtension.java
new file mode 100644
index 000000000..0912d5b0c
--- /dev/null
+++ b/base/util/src/netscape/security/x509/NSCCommentExtension.java
@@ -0,0 +1,230 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.util.PrettyPrintFormat;
+
+/**
+ * This class defines the NSCCommentExtension
+ *
+ * @author asondhi
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class NSCCommentExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4066287070285105375L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.CommentExtension";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "NSCCommentExtension";
+ public static final String INFOS = "infos";
+ public static final ObjectIdentifier OID =
+ new ObjectIdentifier("2.16.840.1.113730.1.13");
+ public String mComment = null;
+
+ // Private data members
+ private Vector<Object> mInfos;
+
+ private PrettyPrintFormat pp = new PrettyPrintFormat(":");
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+
+ os.putIA5String(mComment);
+ // DerOutputStream tmp = new DerOutputStream();
+ // os.write(DerValue.tag_Sequence,tmp);
+ extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a NSCCommentExtension with the Vector of CertificatePolicyInfo.
+ *
+ * @param infos the Vector of CertificatePolicyInfo.
+ */
+ public NSCCommentExtension(boolean critical, String comment) throws IOException {
+ this.mComment = comment;
+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13");
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create a default NSCCommentExtension.
+ */
+ public NSCCommentExtension(boolean critical) {
+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13");
+ this.critical = critical;
+ mInfos = new Vector<Object>(1, 1);
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public NSCCommentExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13");
+
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+
+ mComment = val.getIA5String();
+ }
+
+ /**
+ * Returns a printable representation of the policy extension.
+ */
+ public String toString() {
+ if (mInfos == null)
+ return "";
+ String s = super.toString() + "Netscape Comment [\n"
+ + mInfos.toString() + "]\n";
+
+ return (s);
+ }
+
+ public String toPrint(int indent) {
+ String s;
+ s = "Comment :\n" + pp.indent(indent + 4) +
+ ((mComment == null) ? "" : mComment.trim()) + "\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13");
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ @SuppressWarnings("unchecked")
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(INFOS)) {
+ if (!(obj instanceof Vector)) {
+ throw new IOException("Attribute value should be of" +
+ " type Vector.");
+ }
+ mInfos = (Vector<Object>) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NSCCommentExtension.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(INFOS)) {
+ return (mInfos);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NSCCommentExtension.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(INFOS)) {
+ mInfos = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NSCCommentExtension.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(INFOS);
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/NameConstraintsExtension.java b/base/util/src/netscape/security/x509/NameConstraintsExtension.java
new file mode 100644
index 000000000..948d0d8c9
--- /dev/null
+++ b/base/util/src/netscape/security/x509/NameConstraintsExtension.java
@@ -0,0 +1,315 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.PrettyPrintFormat;
+
+/**
+ * This class defines the Name Constraints Extension.
+ * <p>
+ * The name constraints extension provides permitted and excluded subtrees that place restrictions on names that may be
+ * included within a certificate issued by a given CA. Restrictions may apply to the subject distinguished name or
+ * subject alternative names. Any name matching a restriction in the excluded subtrees field is invalid regardless of
+ * information appearing in the permitted subtrees.
+ * <p>
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * NameConstraints ::= SEQUENCE {
+ * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ * excludedSubtrees [1] GeneralSubtrees OPTIONAL
+ * }
+ * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ * GeneralSubtree ::== SEQUENCE {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL }
+ * BaseDistance ::== INTEGER (0..MAX)
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.10
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class NameConstraintsExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3506940192931244539L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.NameConstraints";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "NameConstraints";
+ public static final String PERMITTED_SUBTREES = "permitted_subtrees";
+ public static final String EXCLUDED_SUBTREES = "excluded_subtrees";
+
+ // Private data members
+ private static final byte TAG_PERMITTED = 0;
+ private static final byte TAG_EXCLUDED = 1;
+
+ private GeneralSubtrees permitted;
+ private GeneralSubtrees excluded;
+
+ private PrettyPrintFormat pp = new PrettyPrintFormat(":");
+
+ // Encode this extension value.
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+
+ DerOutputStream tagged = new DerOutputStream();
+ if ((permitted != null) && (permitted.getSubtrees().size() > 0)) {
+ DerOutputStream tmp = new DerOutputStream();
+ permitted.encode(tmp);
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_PERMITTED), tmp);
+ }
+ if ((excluded != null) && (excluded.getSubtrees().size() > 0)) {
+ DerOutputStream tmp = new DerOutputStream();
+ excluded.encode(tmp);
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_EXCLUDED), tmp);
+ }
+ if (permitted == null && excluded == null) {
+ extensionValue = null; // no need to encode this extension
+ } else {
+ seq.write(DerValue.tag_Sequence, tagged);
+ this.extensionValue = seq.toByteArray();
+ }
+ }
+
+ /**
+ * The default constructor for this class. Either parameter
+ * can be set to null to indicate it is omitted but both
+ * cannot be null.
+ *
+ * @param permitted the permitted GeneralSubtrees (null for optional).
+ * @param excluded the excluded GeneralSubtrees (null for optional).
+ */
+ public NameConstraintsExtension(GeneralSubtrees permitted,
+ GeneralSubtrees excluded)
+ throws IOException {
+ init(false, permitted, excluded);
+ }
+
+ public NameConstraintsExtension(boolean critical,
+ GeneralSubtrees permitted, GeneralSubtrees excluded)
+ throws IOException {
+ init(critical, permitted, excluded);
+ }
+
+ private void init(boolean critical,
+ GeneralSubtrees permitted, GeneralSubtrees excluded)
+ throws IOException {
+ if (permitted == null && excluded == null) {
+ throw new IOException("NameConstraints: Invalid arguments");
+ }
+ this.permitted = permitted;
+ this.excluded = excluded;
+
+ this.extensionId = PKIXExtensions.NameConstraints_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public NameConstraintsExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.NameConstraints_Id;
+ this.critical = critical.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new IOException("Illegal argument type");
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for" +
+ " NameConstraintsExtension.");
+ }
+
+ // NB. this is always encoded with the IMPLICIT tag
+ // The checks only make sense if we assume implicit tagging,
+ // with explicit tagging the form is always constructed.
+ while (val.data.available() != 0) {
+ DerValue opt = val.data.getDerValue();
+
+ if (opt.isContextSpecific(TAG_PERMITTED) && opt.isConstructed()) {
+ if (permitted != null) {
+ throw new IOException("Duplicate permitted " +
+ "GeneralSubtrees in NameConstraintsExtension.");
+ }
+ opt.resetTag(DerValue.tag_Sequence);
+ permitted = new GeneralSubtrees(opt);
+
+ } else if (opt.isContextSpecific(TAG_EXCLUDED) &&
+ opt.isConstructed()) {
+ if (excluded != null) {
+ throw new IOException("Duplicate excluded " +
+ "GeneralSubtrees in NameConstraintsExtension.");
+ }
+ opt.resetTag(DerValue.tag_Sequence);
+ excluded = new GeneralSubtrees(opt);
+ } else
+ throw new IOException("Invalid encoding of " +
+ "NameConstraintsExtension.");
+ }
+ }
+
+ /**
+ * Return the printable string.
+ */
+ public String toString() {
+ return (super.toString() + "NameConstraints: [" +
+ ((permitted == null) ? "" :
+ ("\n Permitted:" + permitted.toString())) +
+ ((excluded == null) ? "" :
+ ("\n Excluded:" + excluded.toString())) + " ]\n");
+ }
+
+ public String toPrint(int indent) {
+ return ("GeneralSubtrees: " +
+ ((permitted == null) ? "" :
+ ("\n" + pp.indent(indent + 2) + "Permitted:" + permitted.toPrint(indent + 4))) +
+ ((excluded == null) ? "" :
+ ("\n" + pp.indent(indent + 2) + "Excluded:" + excluded.toPrint(indent + 4))) + "\n");
+
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (this.extensionValue == null) {
+ this.extensionId = PKIXExtensions.NameConstraints_Id;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
+ if (!(obj instanceof GeneralSubtrees)) {
+ throw new IOException("Attribute value should be"
+ + " of type GeneralSubtrees.");
+ }
+ permitted = (GeneralSubtrees) obj;
+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
+ if (!(obj instanceof GeneralSubtrees)) {
+ throw new IOException("Attribute value should be "
+ + "of type GeneralSubtrees.");
+ }
+ excluded = (GeneralSubtrees) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NameConstraintsExtension.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
+ return (permitted);
+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
+ return (excluded);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NameConstraintsExtension.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
+ permitted = null;
+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
+ excluded = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:NameConstraintsExtension.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(PERMITTED_SUBTREES);
+ elements.addElement(EXCLUDED_SUBTREES);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/NoticeReference.java b/base/util/src/netscape/security/x509/NoticeReference.java
new file mode 100644
index 000000000..150b34f40
--- /dev/null
+++ b/base/util/src/netscape/security/x509/NoticeReference.java
@@ -0,0 +1,94 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the NoticeReference.
+ *
+ * NoticeReference ::= SEQUENCE {
+ * organization DisplayText,
+ * noticeNumbers SEQUENCE OF INTEGER
+ * }
+ *
+ * @author Thomas Kwan
+ */
+public class NoticeReference {
+
+ private DisplayText mOrg = null;
+ private int mNumbers[] = null;
+
+ public NoticeReference(DisplayText org, int numbers[]) {
+ mOrg = org;
+ mNumbers = numbers;
+ }
+
+ public NoticeReference(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for NoticeReference");
+ }
+ mOrg = new DisplayText(val.data.getDerValue());
+ DerValue integers = val.data.getDerValue();
+ if (integers.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for NoticeReference (integers)");
+ }
+ Vector<BigInt> num = new Vector<BigInt>();
+ while (integers.data.available() != 0) {
+ DerValue i = integers.data.getDerValue();
+ BigInt bigI = i.getInteger();
+ num.addElement(bigI);
+ }
+ if (num.size() <= 0)
+ return;
+ mNumbers = new int[num.size()];
+ for (int i = 0; i < num.size(); i++) {
+ mNumbers[i] = num.elementAt(i).toInt();
+ }
+ }
+
+ public DisplayText getOrganization() {
+ return mOrg;
+ }
+
+ public int[] getNumbers() {
+ return mNumbers;
+ }
+
+ /**
+ * Write the NoticeReference to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ mOrg.encode(tmp);
+ DerOutputStream iseq = new DerOutputStream();
+ for (int i = 0; i < mNumbers.length; i++) {
+ iseq.putInteger(new BigInt(mNumbers[i]));
+ }
+ tmp.write(DerValue.tag_Sequence, iseq);
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/OIDMap.java b/base/util/src/netscape/security/x509/OIDMap.java
new file mode 100644
index 000000000..9c732d938
--- /dev/null
+++ b/base/util/src/netscape/security/x509/OIDMap.java
@@ -0,0 +1,303 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * This class defines the mapping from OID & name to classes and vice
+ * versa. Used by CertificateExtensions & PKCS10 to get the java
+ * classes associated with a particular OID/name.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.12
+ */
+public class OIDMap {
+
+ /**
+ * Location for where the OID/Classes maps are stored on
+ * the local system.
+ */
+ public static final String EXTENSIONS_HOME =
+ (System.getProperty("java.home") + File.separator + "lib"
+ + File.separator + "security" + File.separator + "cert"
+ + File.separator);
+ /**
+ * File names for where OIDs and Classes are registered
+ * for V3 extensions.
+ */
+ public static final String EXTENSIONS_OIDS = "x509extensions.oid";
+ public static final String EXTENSIONS_CLASSES = "x509extensions.classes";
+
+ // Make default names easier
+ private static final String ROOT = X509CertImpl.NAME + "." +
+ X509CertInfo.NAME + "." +
+ X509CertInfo.EXTENSIONS;
+ private static final String AUTH_KEY_IDENTIFIER = ROOT + "." +
+ AuthorityKeyIdentifierExtension.NAME;
+ private static final String SUB_KEY_IDENTIFIER = ROOT + "." +
+ SubjectKeyIdentifierExtension.NAME;
+ private static final String KEY_USAGE = ROOT + "." +
+ KeyUsageExtension.NAME;
+ private static final String PRIVATE_KEY_USAGE = ROOT + "." +
+ PrivateKeyUsageExtension.NAME;
+ private static final String POLICY_MAPPINGS = ROOT + "." +
+ PolicyMappingsExtension.NAME;
+ private static final String SUB_ALT_NAME = ROOT + "." +
+ SubjectAlternativeNameExtension.NAME;
+ private static final String ISSUER_ALT_NAME = ROOT + "." +
+ IssuerAlternativeNameExtension.NAME;
+ private static final String BASIC_CONSTRAINTS = ROOT + "." +
+ BasicConstraintsExtension.NAME;
+ private static final String NAME_CONSTRAINTS = ROOT + "." +
+ NameConstraintsExtension.NAME;
+ private static final String POLICY_CONSTRAINTS = ROOT + "." +
+ PolicyConstraintsExtension.NAME;
+ private static final String CERT_POLICIES = //ROOT + "." +
+ CertificatePoliciesExtension.NAME;
+ private static final String SUBJ_DIR_ATTR = //ROOT + "." +
+ SubjectDirAttributesExtension.NAME;
+ public static final String EXT_KEY_USAGE_NAME = "ExtendedKeyUsageExtension";
+ public static final String EXT_INHIBIT_ANY_POLICY_NAME = "InhibitAnyPolicyExtension";
+ private static final String EXT_KEY_USAGE = //ROOT + "." +
+ EXT_KEY_USAGE_NAME;
+
+ private static final String CRL_NUMBER = ROOT + "." +
+ CRLNumberExtension.NAME;
+ private static final String CRL_REASON = ROOT + "." +
+ CRLReasonExtension.NAME;
+
+ private static final Hashtable<ObjectIdentifier, String> oid2Name = new Hashtable<ObjectIdentifier, String>();
+ private static final Hashtable<String, ObjectIdentifier> name2OID = new Hashtable<String, ObjectIdentifier>();
+ private static final Hashtable<String, String> name2Class = new Hashtable<String, String>();
+
+ // Initialize recognized extensions from EXTENSIONS_{OIDS/CLASSES} files
+ static {
+ loadNames();
+ loadClasses();
+ }
+
+ // Load the default name to oid map (EXTENSIONS_OIDS)
+ private static void loadNamesDefault(Properties props) {
+ props.put(SUB_KEY_IDENTIFIER, "2.5.29.14");
+ props.put(KEY_USAGE, "2.5.29.15");
+ props.put(PRIVATE_KEY_USAGE, "2.5.29.16");
+ props.put(SUB_ALT_NAME, "2.5.29.17");
+ props.put(ISSUER_ALT_NAME, "2.5.29.18");
+ props.put(BASIC_CONSTRAINTS, "2.5.29.19");
+ props.put(CRL_NUMBER, "2.5.29.20");
+ props.put(CRL_REASON, "2.5.29.21");
+ props.put(NAME_CONSTRAINTS, "2.5.29.30");
+ props.put(POLICY_MAPPINGS, "2.5.29.33");
+ props.put(POLICY_CONSTRAINTS, "2.5.29.36");
+ props.put(CERT_POLICIES, "2.5.29.32");
+ props.put(AUTH_KEY_IDENTIFIER, "2.5.29.35");
+ props.put(SUBJ_DIR_ATTR, "2.5.29.9");
+ props.put(EXT_KEY_USAGE, "2.5.29.37");
+ }
+
+ // Load the default name to class map (EXTENSIONS_CLASSES)
+ private static void loadClassDefault(Properties props) {
+ props.put(AUTH_KEY_IDENTIFIER,
+ "netscape.security.x509.AuthorityKeyIdentifierExtension");
+ props.put(SUB_KEY_IDENTIFIER,
+ "netscape.security.x509.SubjectKeyIdentifierExtension");
+ props.put(KEY_USAGE,
+ "netscape.security.x509.KeyUsageExtension");
+ props.put(PRIVATE_KEY_USAGE,
+ "netscape.security.x509.PrivateKeyUsageExtension");
+ props.put(POLICY_MAPPINGS,
+ "netscape.security.x509.PolicyMappingsExtension");
+ props.put(SUB_ALT_NAME,
+ "netscape.security.x509.SubjectAlternativeNameExtension");
+ props.put(ISSUER_ALT_NAME,
+ "netscape.security.x509.IssuerAlternativeNameExtension");
+ props.put(BASIC_CONSTRAINTS,
+ "netscape.security.x509.BasicConstraintsExtension");
+ props.put(NAME_CONSTRAINTS,
+ "netscape.security.x509.NameConstraintsExtension");
+ props.put(POLICY_CONSTRAINTS,
+ "netscape.security.x509.PolicyConstraintsExtension");
+ props.put(CERT_POLICIES,
+ "netscape.security.x509.CertificatePoliciesExtension");
+ props.put(SUBJ_DIR_ATTR,
+ "netscape.security.x509.SubjectDirAttributesExtension");
+ props.put(EXT_KEY_USAGE,
+ "netscape.security.extensions.ExtendedKeyUsageExtension");
+ props.put(CRL_NUMBER, "netscape.security.x509.CRLNumberExtension");
+ props.put(CRL_REASON, "netscape.security.x509.CRLReasonExtension");
+ }
+
+ // Return the file along with location
+ private static File certificatePropFile(String fileName) {
+ return (new File(EXTENSIONS_HOME + fileName));
+ }
+
+ // Load the names to oid map
+ private static void loadNames() {
+ Properties props = new Properties();
+ File namesMap = certificatePropFile(EXTENSIONS_OIDS);
+
+ if (!namesMap.exists()) {
+ loadNamesDefault(props);
+ } else {
+ try {
+ FileInputStream fis = new FileInputStream(namesMap);
+ props.load(fis);
+ fis.close();
+ } catch (IOException e) {
+ loadNamesDefault(props);
+ }
+ }
+
+ Iterator<String> names = props.stringPropertyNames().iterator();
+ while (names.hasNext()) {
+ String name = names.next();
+ String oidName = props.getProperty(name);
+ ObjectIdentifier oid = new ObjectIdentifier(oidName);
+
+ name2OID.put(name, oid);
+ oid2Name.put(oid, name);
+ }
+ }
+
+ // Load the names to classes map
+ private static void loadClasses() {
+ Properties props = new Properties();
+ File classMap = certificatePropFile(EXTENSIONS_CLASSES);
+
+ if (!classMap.exists()) {
+ loadClassDefault(props);
+ } else {
+ try {
+ FileInputStream fis = new FileInputStream(classMap);
+ props.load(fis);
+ } catch (IOException e) {
+ loadClassDefault(props);
+ }
+ }
+
+ Iterator<String> names = props.stringPropertyNames().iterator();
+ while (names.hasNext()) {
+ String name = names.next();
+ String className = props.getProperty(name);
+
+ name2Class.put(name, className);
+ }
+ }
+
+ /**
+ * Add a name to lookup table.
+ *
+ * @param className the name of the fully qualified class implementing
+ * the asn object.
+ * @param oid the string representation of the object identifier for
+ * the class.
+ * @param name the name of the attribute.
+ * @exception CertificateException on errors.
+ */
+ public static void addAttribute(String className, String oid, String name)
+ throws CertificateException {
+ ObjectIdentifier objId = new ObjectIdentifier(oid);
+ if (oid2Name.get(objId) != null) {
+ throw new CertificateException("Object identifier already exists.");
+ }
+ if (name2OID.get(name) != null) {
+ throw new CertificateException("Name already exists.");
+ }
+ if (name2Class.get(className) != null) {
+ throw new CertificateException("Class already exists.");
+ }
+ oid2Name.put(objId, name);
+ name2OID.put(name, objId);
+ name2Class.put(name, className);
+ }
+
+ /**
+ * Return user friendly name associated with the OID.
+ *
+ * @param oid the name of the object identifier to be returned.
+ * @return the user friendly name or null if no name
+ * is registered for this oid.
+ */
+ public static String getName(ObjectIdentifier oid) {
+ return (String) oid2Name.get(oid);
+ }
+
+ /**
+ * Return Object identifier for user friendly name.
+ *
+ * @param name the user friendly name.
+ * @return the Object Identifier or null if no oid
+ * is registered for this name.
+ */
+ public static ObjectIdentifier getOID(String name) {
+ return (ObjectIdentifier) name2OID.get(name);
+ }
+
+ /**
+ * Return the java class object associated with the user friendly name.
+ *
+ * @param name the user friendly name.
+ * @exception CertificateException if class cannot be instantiated.
+ */
+ public static Class<?> getClass(String name) throws CertificateException {
+ String className = (String) name2Class.get(name);
+ if (className == null)
+ return null;
+ try {
+ Class<?> extClass = Class.forName(className);
+ return (extClass);
+ } catch (Exception e) {
+ throw new CertificateException("Error instantiating class for "
+ + name + " " + e.toString());
+ }
+ }
+
+ /**
+ * Return the java class object associated with the object identifier..
+ *
+ * @param oid the name of the object identifier to be returned.
+ * @exception CertificateException if class cannot be instatiated.
+ */
+ public static Class<?> getClass(ObjectIdentifier oid)
+ throws CertificateException {
+ String name = getName(oid);
+ if (name == null)
+ return null;
+ String className = (String) name2Class.get(name);
+ if (className == null)
+ return null;
+ try {
+ Class<?> extClass = Class.forName(className);
+ return (extClass);
+ } catch (Exception e) {
+ throw new CertificateException("Error instantiating class for "
+ + name + " " + e.toString());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/OIDName.java b/base/util/src/netscape/security/x509/OIDName.java
new file mode 100644
index 000000000..e5c1b7ac3
--- /dev/null
+++ b/base/util/src/netscape/security/x509/OIDName.java
@@ -0,0 +1,90 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * This class implements the OIDName as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.3
+ * @see GeneralName
+ * @see GeneralNames
+ * @see GeneralNameInterface
+ */
+public class OIDName implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 9198510631835117121L;
+ private ObjectIdentifier oid;
+
+ /**
+ * Create the OIDName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER OIDName.
+ * @exception IOException on error.
+ */
+ public OIDName(DerValue derValue) throws IOException {
+ oid = derValue.getOID();
+ }
+
+ /**
+ * Create the OIDName object with the specified name.
+ *
+ * @param name the OIDName.
+ */
+ public OIDName(ObjectIdentifier oid) {
+ this.oid = oid;
+ }
+
+ public OIDName(String oid) {
+ this.oid = new ObjectIdentifier(oid);
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_OID);
+ }
+
+ /**
+ * Encode the OID name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the OIDName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putOID(oid);
+ }
+
+ /**
+ * Convert the name into user readable string.
+ */
+ public String toString() {
+ return ("OIDName: " + oid.toString());
+ }
+}
diff --git a/base/util/src/netscape/security/x509/OtherName.java b/base/util/src/netscape/security/x509/OtherName.java
new file mode 100644
index 000000000..38d3a0af3
--- /dev/null
+++ b/base/util/src/netscape/security/x509/OtherName.java
@@ -0,0 +1,208 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * This class implements the OtherName as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id
+ * }
+ *
+ * @see GeneralName
+ * @see GeneralNameInterface
+ * @see GeneralNames
+ *
+ * @version 1.2
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class OtherName implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3533614377346132611L;
+ private ObjectIdentifier mOID = null;
+ private byte[] mData = null;
+
+ /**
+ * Create the IPAddressName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER IPAddressName.
+ * @exception IOException on error.
+ */
+ public OtherName(DerValue derValue) throws IOException {
+ decodeThis(derValue);
+ }
+
+ public OtherName(ObjectIdentifier oid, byte data[]) {
+ mOID = oid;
+ DerOutputStream dos = new DerOutputStream();
+ try {
+ dos.putDerValue(new DerValue(data));
+ } catch (IOException e) {
+ }
+ mData = dos.toByteArray();
+ }
+
+ /**
+ * Constructs a string-based other name.
+ */
+ public OtherName(ObjectIdentifier oid, byte tag, String value) {
+ mOID = oid;
+ DerOutputStream dos = new DerOutputStream();
+ try {
+ if (tag == DerValue.tag_PrintableString) {
+ dos.putPrintableString(value);
+ } else if (tag == DerValue.tag_IA5String) {
+ dos.putIA5String(value);
+ } else if (tag == DerValue.tag_BMPString) {
+ dos.putBMPString(value);
+ } else if (tag == DerValue.tag_UTF8String) {
+ dos.putUTF8String(value);
+ }
+ } catch (IOException e) {
+ }
+ mData = dos.toByteArray();
+ }
+
+ public OtherName(ObjectIdentifier oid, String value) {
+ mOID = oid;
+ DerOutputStream dos = new DerOutputStream();
+ try {
+ dos.putPrintableString(value);
+ } catch (IOException e) {
+ }
+ mData = dos.toByteArray();
+ }
+
+ /**
+ * Create the IPAddressName object with the specified name.
+ *
+ * @param name the IPAddressName.
+ */
+ public OtherName(byte[] data) {
+ try {
+ decodeThis(new DerValue(data));
+ } catch (IOException e) {
+ }
+ }
+
+ public ObjectIdentifier getOID() {
+ return mOID;
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_ANY);
+ }
+
+ /**
+ * Encode the IPAddress name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the IPAddressName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ //encoding the attributes
+ tmp.putOID(mOID);
+ DerOutputStream tmp1 = new DerOutputStream();
+ tmp1.write(mData);
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
+ (byte) 0x80), tmp1);
+
+ out.write(DerValue.tag_SequenceOf, tmp);
+ }
+
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ decodeThis(val);
+ }
+
+ // Decode this extension value
+ private void decodeThis(DerValue derVal) throws IOException {
+
+ // if (derVal.tag != DerValue.tag_Sequence) {
+ // throw new IOException("Invalid encoding for other name");
+ // }
+
+ // Decode all the Attributes
+ mOID = derVal.data.getOID();
+ // skip tag
+ DerValue tag = derVal.data.getDerValue();
+ // read data
+ DerValue data = tag.data.getDerValue();
+ mData = data.toByteArray();
+ }
+
+ public byte[] getValue() {
+ return mData;
+ }
+
+ /**
+ * Return a printable string of IPaddress
+ */
+ public String toString() {
+ if (mData != null) {
+ try {
+ DerValue data = new DerValue(mData);
+ if (data.tag == DerValue.tag_PrintableString) {
+ return "OtherName: (PrintableString)" + mOID + "," + data.getPrintableString();
+ } else if (data.tag == DerValue.tag_IA5String) {
+ return "OtherName: (IA5String)" + mOID + "," + data.getIA5String();
+ } else if (data.tag == DerValue.tag_BMPString) {
+ return "OtherName: (BMPString)" + mOID + "," + data.getIA5String();
+ } else if (data.tag == DerValue.tag_UTF8String) {
+ return "OtherName: (UTF8String)" + mOID + "," + data.getUTF8String();
+ } else {
+ return "OtherName: (Any)" + mOID + "," + toStr(data.toByteArray());
+ }
+ } catch (IOException e) {
+
+ return "OtherName: (Any)" + mOID + "," + toStr(mData);
+ }
+ } else {
+ return "OtherName: ";
+ }
+ }
+
+ public String toStr(byte data[]) {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ if ((data[i] & 0xff) < 16) {
+ b.append("0");
+ }
+ b.append(Integer.toString((int) (data[i] & 0xff), 0x10));
+ }
+ return b.toString();
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PKIXExtensions.java b/base/util/src/netscape/security/x509/PKIXExtensions.java
new file mode 100644
index 000000000..9946a5c57
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PKIXExtensions.java
@@ -0,0 +1,185 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Lists all the object identifiers of the X509 extensions of the PKIX profile.
+ *
+ * <p>
+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a
+ * "Driving License Certificate" could have the driving license number as a extension.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ *
+ * @see Extension
+ *
+ * @version 1.4
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public class PKIXExtensions {
+ // The object identifiers
+ private static final int AuthorityKey_data[] = { 2, 5, 29, 35 };
+ private static final int SubjectKey_data[] = { 2, 5, 29, 14 };
+ private static final int KeyUsage_data[] = { 2, 5, 29, 15 };
+ private static final int PrivateKeyUsage_data[] = { 2, 5, 29, 16 };
+ private static final int CertificatePolicies_data[] = { 2, 5, 29, 32 };
+ private static final int PolicyMappings_data[] = { 2, 5, 29, 33 };
+ private static final int SubjectAlternativeName_data[] = { 2, 5, 29, 17 };
+ private static final int IssuerAlternativeName_data[] = { 2, 5, 29, 18 };
+ private static final int SubjectDirectoryAttributes_data[] = { 2, 5, 29, 9 };
+ private static final int BasicConstraints_data[] = { 2, 5, 29, 19 };
+ private static final int NameConstraints_data[] = { 2, 5, 29, 30 };
+ private static final int PolicyConstraints_data[] = { 2, 5, 29, 36 };
+ private static final int CRLDistributionPoints_data[] = { 2, 5, 29, 31 };
+ private static final int CRLNumber_data[] = { 2, 5, 29, 20 };
+ private static final int IssuingDistributionPoint_data[] = { 2, 5, 29, 28 };
+ private static final int DeltaCRLIndicator_data[] = { 2, 5, 29, 27 };
+ private static final int ReasonCode_data[] = { 2, 5, 29, 21 };
+ private static final int HoldInstructionCode_data[] = { 2, 5, 29, 23 };
+ private static final int InvalidityDate_data[] = { 2, 5, 29, 24 };
+ private static final int CertificateIssuer_data[] = { 2, 5, 29, 29 };
+ private static final int FreshestCRL_data[] = { 2, 5, 29, 46 };
+
+ /**
+ * Identifies the particular public key used to sign the certificate.
+ */
+ public static final ObjectIdentifier AuthorityKey_Id = new ObjectIdentifier(AuthorityKey_data);
+
+ /**
+ * Identifies the particular public key used in an application.
+ */
+ public static final ObjectIdentifier SubjectKey_Id = new ObjectIdentifier(SubjectKey_data);
+
+ /**
+ * Defines the purpose of the key contained in the certificate.
+ */
+ public static final ObjectIdentifier KeyUsage_Id = new ObjectIdentifier(KeyUsage_data);
+
+ /**
+ * Allows the certificate issuer to specify a different validity period
+ * for the private key than the certificate.
+ */
+ public static final ObjectIdentifier PrivateKeyUsage_Id = new ObjectIdentifier(PrivateKeyUsage_data);
+
+ /**
+ * Contains the sequence of policy information terms.
+ */
+ public static final ObjectIdentifier CertificatePolicies_Id = new ObjectIdentifier(CertificatePolicies_data);
+
+ /**
+ * Lists pairs of objectidentifiers of policies considered equivalent by the
+ * issuing CA to the subject CA.
+ */
+ public static final ObjectIdentifier PolicyMappings_Id = new ObjectIdentifier(PolicyMappings_data);
+
+ /**
+ * Allows additional identities to be bound to the subject of the certificate.
+ */
+ public static final ObjectIdentifier SubjectAlternativeName_Id = new ObjectIdentifier(SubjectAlternativeName_data);
+
+ /**
+ * Allows additional identities to be associated with the certificate issuer.
+ */
+ public static final ObjectIdentifier IssuerAlternativeName_Id =
+ new ObjectIdentifier(IssuerAlternativeName_data);
+
+ /**
+ * Identifies additional directory attributes.
+ * This extension is always non-critical.
+ */
+ public static final ObjectIdentifier SubjectDirectoryAttributes_Id = new ObjectIdentifier(
+ SubjectDirectoryAttributes_data);
+
+ /**
+ * Identifies whether the subject of the certificate is a CA and how deep
+ * a certification path may exist through that CA.
+ */
+ public static final ObjectIdentifier BasicConstraints_Id =
+ new ObjectIdentifier(BasicConstraints_data);
+
+ /**
+ * Provides for permitted and excluded subtrees that place restrictions
+ * on names that may be included within a certificate issued by a given CA.
+ */
+ public static final ObjectIdentifier NameConstraints_Id = new ObjectIdentifier(NameConstraints_data);
+
+ /**
+ * Used to either prohibit policy mapping or limit the set of policies
+ * that can be in subsequent certificates.
+ */
+ public static final ObjectIdentifier PolicyConstraints_Id = new ObjectIdentifier(PolicyConstraints_data);
+
+ /**
+ * Identifies how CRL information is obtained.
+ */
+ public static final ObjectIdentifier CRLDistributionPoints_Id = new ObjectIdentifier(CRLDistributionPoints_data);
+
+ /**
+ * Conveys a monotonically increasing sequence number for each CRL
+ * issued by a given CA.
+ */
+ public static final ObjectIdentifier CRLNumber_Id = new ObjectIdentifier(CRLNumber_data);
+
+ /**
+ * Identifies the CRL distribution point for a particular CRL.
+ */
+ public static final ObjectIdentifier IssuingDistributionPoint_Id = new ObjectIdentifier(
+ IssuingDistributionPoint_data);
+
+ /**
+ * Identifies the delta CRL.
+ */
+ public static final ObjectIdentifier DeltaCRLIndicator_Id = new ObjectIdentifier(DeltaCRLIndicator_data);
+
+ /**
+ * Identifies the reason for the certificate revocation.
+ */
+ public static final ObjectIdentifier ReasonCode_Id = new ObjectIdentifier(ReasonCode_data);
+
+ /**
+ * This extension provides a registered instruction identifier indicating
+ * the action to be taken, after encountering a certificate that has been
+ * placed on hold.
+ */
+ public static final ObjectIdentifier HoldInstructionCode_Id = new ObjectIdentifier(HoldInstructionCode_data);
+
+ /**
+ * Identifies the date on which it is known or suspected that the private
+ * key was compromised or that the certificate otherwise became invalid.
+ */
+ public static final ObjectIdentifier InvalidityDate_Id = new ObjectIdentifier(InvalidityDate_data);
+
+ /**
+ * Identifies the date on which it is known or suspected that the private
+ * key was compromised or that the certificate otherwise became invalid.
+ */
+ public static final ObjectIdentifier CertificateIssuer_Id = new ObjectIdentifier(CertificateIssuer_data);
+
+ /**
+ * Identifies how delta CRL information is obtained.
+ */
+ public static final ObjectIdentifier FreshestCRL_Id = new ObjectIdentifier(FreshestCRL_data);
+
+}
diff --git a/base/util/src/netscape/security/x509/PolicyConstraint.java b/base/util/src/netscape/security/x509/PolicyConstraint.java
new file mode 100644
index 000000000..22f9cebed
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PolicyConstraint.java
@@ -0,0 +1,136 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the PolicyConstraint ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class PolicyConstraint {
+ private static final byte TAG_SET = 0;
+ private static final byte TAG_REQUIRE = 1;
+ private static final byte TAG_INHIBIT = 2;
+
+ private CertificatePolicySet set = null;
+ private int require = -1;
+ private int inhibit = -1;
+
+ /**
+ * The default constructor for this object
+ *
+ * @param set the CertificatePolicySet (null for optional).
+ * @param require require explicit policy (-1 for optional).
+ * @param inhibit inhibit policy mapping (-1 for optional).
+ */
+ public PolicyConstraint(CertificatePolicySet set, int require, int inhibit) {
+ this.set = set;
+ this.require = require;
+ this.inhibit = inhibit;
+ }
+
+ /**
+ * Create the PolicyConstraint from the DerValue.
+ *
+ * @param val the DerValue of the PolicyConstraint.
+ * @exception IOException on decoding errors.
+ */
+ public PolicyConstraint(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Sequence tag missing for PolicyConstraint.");
+ }
+ DerInputStream in = val.data;
+ while (in != null && in.available() != 0) {
+ DerValue next = in.getDerValue();
+ switch (next.tag & 0x1f) {
+ case TAG_SET:
+ this.set = new CertificatePolicySet(next.data);
+ break;
+
+ case TAG_REQUIRE:
+ next = next.data.getDerValue();
+ this.require = (next.getInteger()).toInt();
+ break;
+
+ case TAG_INHIBIT:
+ next = next.data.getDerValue();
+ this.inhibit = (next.getInteger()).toInt();
+ break;
+
+ default:
+ throw new IOException("Invalid tag option for PolicyConstraint.");
+ }
+ }
+ }
+
+ /**
+ * Return user readable form of the object.
+ */
+ public String toString() {
+ String s = ((set != null) ?
+ "PolicyConstraint: [\n"
+ + " PolicySet:[" + set.toString() + "]\n"
+ + " Require:" + require + "\n"
+ + " Inhibit:" + inhibit + "\n"
+ + "]\n" :
+ "PolicyConstraint: [\n"
+ + " PolicySet:[null]\n"
+ + " Require:" + require + "\n"
+ + " Inhibit:" + inhibit + "\n"
+ + "]\n");
+ return (s);
+ }
+
+ /**
+ * Encode the object to the output stream.
+ *
+ * @param out the DerOutputStream to encode the object to.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tagged = new DerOutputStream();
+
+ if (set != null) {
+ DerOutputStream tmp = new DerOutputStream();
+ set.encode(tmp);
+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_SET), tmp);
+ }
+ if (require != -1) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(require));
+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_REQUIRE), tmp);
+ }
+ if (inhibit != -1) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(inhibit));
+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, TAG_INHIBIT), tmp);
+ }
+ out.write(DerValue.tag_Sequence, tagged);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PolicyConstraintsExtension.java b/base/util/src/netscape/security/x509/PolicyConstraintsExtension.java
new file mode 100644
index 000000000..7d98b21ba
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PolicyConstraintsExtension.java
@@ -0,0 +1,306 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the certificate extension which specifies the
+ * Policy constraints.
+ * <p>
+ * The policy constraints extension can be used in certificates issued to CAs. The policy constraints extension
+ * constrains path validation in two ways. It can be used to prohibit policy mapping or require that each certificate in
+ * a path contain an acceptable policy identifier.
+ * <p>
+ * The ASN.1 syntax for this is (IMPLICIT tagging is defined in the module definition):
+ *
+ * <pre>
+ * PolicyConstraints ::= SEQUENCE {
+ * requireExplicitPolicy [0] SkipCerts OPTIONAL,
+ * inhibitPolicyMapping [1] SkipCerts OPTIONAL
+ * }
+ * SkipCerts ::= INTEGER (0..MAX)
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class PolicyConstraintsExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3723759691127622370L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.PolicyConstraints";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "PolicyConstraints";
+ public static final String REQUIRE = "require";
+ public static final String INHIBIT = "inhibit";
+
+ private static final byte TAG_REQUIRE = 0;
+ private static final byte TAG_INHIBIT = 1;
+
+ private int require = -1;
+ private int inhibit = -1;
+
+ // Encode this extension value.
+ private void encodeThis() throws IOException {
+ DerOutputStream tagged = new DerOutputStream();
+ DerOutputStream seq = new DerOutputStream();
+
+ if (require != -1) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(require));
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_REQUIRE), tmp);
+ }
+ if (inhibit != -1) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putInteger(new BigInt(inhibit));
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_INHIBIT), tmp);
+ }
+ seq.write(DerValue.tag_Sequence, tagged);
+ extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * Create a PolicyConstraintsExtension object with criticality and
+ * both require explicit policy and inhibit policy mapping.
+ *
+ * @param critical whether this extension should be critical
+ * @param require require explicit policy (-1 for optional).
+ * @param inhibit inhibit policy mapping (-1 for optional).
+ */
+ public PolicyConstraintsExtension(boolean crit, int require, int inhibit)
+ throws IOException {
+ init(crit, require, inhibit);
+ }
+
+ /**
+ * Create a PolicyConstraintsExtension object with both
+ * require explicit policy and inhibit policy mapping.
+ *
+ * @param require require explicit policy (-1 for optional).
+ * @param inhibit inhibit policy mapping (-1 for optional).
+ */
+ public PolicyConstraintsExtension(int require, int inhibit)
+ throws IOException {
+ init(false, require, inhibit);
+ }
+
+ private void init(boolean crit, int require, int inhibit)
+ throws IOException {
+ this.require = require;
+ this.inhibit = inhibit;
+ this.extensionId = PKIXExtensions.PolicyConstraints_Id;
+ this.critical = crit;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from its DER encoded value and criticality.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public PolicyConstraintsExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.PolicyConstraints_Id;
+ this.critical = critical.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new IOException("Illegal argument type");
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Sequence tag missing for PolicyConstraint.");
+ }
+ DerInputStream in = val.data;
+ while (in != null && in.available() != 0) {
+ DerValue next = in.getDerValue();
+
+ if (next.isContextSpecific(TAG_REQUIRE) && !next.isConstructed()) {
+ if (this.require != -1)
+ throw new IOException("Duplicate requireExplicitPolicy" +
+ "found in the PolicyConstraintsExtension");
+ next.resetTag(DerValue.tag_Integer);
+ this.require = (next.getInteger()).toInt();
+
+ } else if (next.isContextSpecific(TAG_INHIBIT) &&
+ !next.isConstructed()) {
+ if (this.inhibit != -1)
+ throw new IOException("Duplicate inhibitPolicyMapping" +
+ "found in the PolicyConstraintsExtension");
+ next.resetTag(DerValue.tag_Integer);
+ this.inhibit = (next.getInteger()).toInt();
+ } else
+ throw new IOException("Invalid encoding of PolicyConstraint");
+ }
+ }
+
+ /**
+ * Return the extension as user readable string.
+ */
+ public String toString() {
+ String s;
+ s = super.toString() + "PolicyConstraints: [" + " Require: ";
+ if (require == -1)
+ s += "unspecified;";
+ else
+ s += require + ";";
+ s += "\tInhibit: ";
+ if (inhibit == -1)
+ s += "unspecified";
+ else
+ s += inhibit;
+ s += " ]\n";
+ return s;
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.PolicyConstraints_Id;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (!(obj instanceof Integer)) {
+ throw new IOException("Attribute value should be of type Integer.");
+ }
+ if (name.equalsIgnoreCase(REQUIRE)) {
+ require = ((Integer) obj).intValue();
+ } else if (name.equalsIgnoreCase(INHIBIT)) {
+ inhibit = ((Integer) obj).intValue();
+ } else {
+ throw new IOException("Attribute name " + "[" + name + "]" +
+ " not recognized by " +
+ "CertAttrSet:PolicyConstraints.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(REQUIRE)) {
+ return Integer.valueOf(require);
+ } else if (name.equalsIgnoreCase(INHIBIT)) {
+ return Integer.valueOf(inhibit);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:PolicyConstraints.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(REQUIRE)) {
+ require = -1;
+ } else if (name.equalsIgnoreCase(INHIBIT)) {
+ inhibit = -1;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:PolicyConstraints.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(REQUIRE);
+ elements.addElement(INHIBIT);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * returns the requireExplicitMapping parameter.
+ */
+ public int getRequireExplicitMapping() {
+ return require;
+ }
+
+ /**
+ * returns the inhibitPolicyMapping parameter.
+ */
+ public int getInhibitPolicyMapping() {
+ return inhibit;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PolicyMappingsExtension.java b/base/util/src/netscape/security/x509/PolicyMappingsExtension.java
new file mode 100644
index 000000000..9bdfb611b
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PolicyMappingsExtension.java
@@ -0,0 +1,258 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Policy Mappings Extension.
+ *
+ * This extension, if present, identifies the certificate policies considered
+ * identical between the issuing and the subject CA.
+ * <p>
+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a
+ * "Driving License Certificate" could have the driving license number as a extension.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class PolicyMappingsExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4023336164621135851L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.PolicyMappings";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "PolicyMappings";
+ public static final String MAP = "map";
+
+ // Private data members
+ private Vector<CertificatePolicyMap> maps = null;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < maps.size(); i++) {
+ ((CertificatePolicyMap) maps.elementAt(i)).encode(tmp);
+ }
+ os.write(DerValue.tag_Sequence, tmp);
+ extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a PolicyMappings with the Vector of CertificatePolicyMap.
+ *
+ * @param maps the Vector of CertificatePolicyMap.
+ */
+ public PolicyMappingsExtension(Vector<CertificatePolicyMap> map) throws IOException {
+ init(false, map);
+ }
+
+ /**
+ * Create a PolicyMappings with the Vector of CertificatePolicyMap.
+ *
+ * @param maps the Vector of CertificatePolicyMap.
+ */
+ public PolicyMappingsExtension(boolean critical, Vector<CertificatePolicyMap> map)
+ throws IOException {
+ init(critical, map);
+ }
+
+ /**
+ * init policy with criticality and map.
+ */
+ private void init(boolean critical, Vector<CertificatePolicyMap> map) throws IOException {
+ this.maps = map;
+ this.extensionId = PKIXExtensions.PolicyMappings_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ /**
+ * Create a default PolicyMappingsExtension.
+ */
+ public PolicyMappingsExtension() {
+ extensionId = PKIXExtensions.PolicyMappings_Id;
+ critical = false;
+ maps = new Vector<CertificatePolicyMap>(1, 1);
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public PolicyMappingsExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.PolicyMappings_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for " +
+ "PolicyMappingsExtension.");
+ }
+ maps = new Vector<CertificatePolicyMap>(1, 1);
+ while (val.data.available() != 0) {
+ DerValue seq = val.data.getDerValue();
+ CertificatePolicyMap map = new CertificatePolicyMap(seq);
+ maps.addElement(map);
+ }
+ }
+
+ /**
+ * Returns a printable representation of the policy map.
+ */
+ public String toString() {
+ if (maps == null)
+ return "";
+ String s = super.toString() + "PolicyMappings [\n"
+ + maps.toString() + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.PolicyMappings_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ @SuppressWarnings("unchecked")
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(MAP)) {
+ if (!(obj instanceof Vector)) {
+ throw new IOException("Attribute value should be of" +
+ " type Vector.");
+ }
+ maps = (Vector<CertificatePolicyMap>) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:PolicyMappingsExtension.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(MAP)) {
+ return (maps);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:PolicyMappingsExtension.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(MAP)) {
+ maps = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:PolicyMappingsExtension.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(MAP);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Returns an enumeration of the mappings in the extension.
+ */
+ public Enumeration<CertificatePolicyMap> getMappings() {
+ if (maps == null)
+ return null;
+ return maps.elements();
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PolicyQualifierInfo.java b/base/util/src/netscape/security/x509/PolicyQualifierInfo.java
new file mode 100644
index 000000000..56d3e32c0
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PolicyQualifierInfo.java
@@ -0,0 +1,118 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Represent the PolicyQualifierInfo.
+ *
+ * policyQualifierInfo ::= SEQUENCE {
+ * policyQualifierId PolicyQualifierId
+ * qualifier ANY DEFINED BY policyQualifierId
+ * }
+ *
+ * @author Thomas Kwan
+ */
+public class PolicyQualifierInfo implements java.io.Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2930016944517192379L;
+ public static final int OID_CPS[] = { 1, 3, 6, 1, 5, 5, 7, 2, 1 };
+ public static final ObjectIdentifier QT_CPS = new
+ ObjectIdentifier(OID_CPS);
+
+ public static final int OID_UNOTICE[] = { 1, 3, 6, 1, 5, 5, 7, 2, 2 };
+ public static final ObjectIdentifier QT_UNOTICE = new
+ ObjectIdentifier(OID_UNOTICE);
+
+ private ObjectIdentifier mId = null;
+ private Qualifier mQualifier = null;
+
+ /**
+ * Create a PolicyQualifierInfo
+ *
+ * @param id the ObjectIdentifier for the policy id.
+ */
+ public PolicyQualifierInfo(ObjectIdentifier id, Qualifier qualifier) {
+ mId = id;
+ mQualifier = qualifier;
+ }
+
+ /**
+ * Create the object from its Der encoded value.
+ *
+ * @param val the DER encoded value for the same.
+ */
+ public PolicyQualifierInfo(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for PolicyQualifierInfo.");
+ }
+ DerValue did = val.data.getDerValue();
+ mId = did.getOID();
+ if (val.data.available() != 0) {
+ DerValue qualifier = val.data.getDerValue();
+ if (qualifier.tag == DerValue.tag_IA5String) {
+ mQualifier = new CPSuri(qualifier);
+ } else {
+ mQualifier = new UserNotice(qualifier);
+ }
+ }
+ }
+
+ public ObjectIdentifier getId() {
+ return mId;
+ }
+
+ /**
+ * Returns object of type CPSuri or UserNotice.
+ */
+ public Qualifier getQualifier() {
+ return mQualifier;
+ }
+
+ /**
+ * Returns a printable representation of the CertificatePolicyId.
+ */
+ public String toString() {
+ String s = "PolicyQualifierInfo: [";
+ s = s + getId() + " " + getQualifier();
+ s = s + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the PolicyQualifier to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putOID(mId);
+ mQualifier.encode(tmp);
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PolicyQualifiers.java b/base/util/src/netscape/security/x509/PolicyQualifiers.java
new file mode 100644
index 000000000..ee756f50a
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PolicyQualifiers.java
@@ -0,0 +1,107 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the PolicyQualifiers.
+ *
+ * policyQualifiers ::= SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo
+ *
+ * @author Thomas Kwan
+ */
+public class PolicyQualifiers implements java.io.Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6932694408774694516L;
+ private Vector<PolicyQualifierInfo> mInfo = new Vector<PolicyQualifierInfo>();
+
+ /**
+ * Create a PolicyQualifiers with the ObjectIdentifier.
+ *
+ * @param id the ObjectIdentifier for the policy id.
+ */
+ public PolicyQualifiers() {
+ }
+
+ /**
+ * Create the object from its Der encoded value.
+ *
+ * @param val the DER encoded value for the same.
+ */
+ public PolicyQualifiers(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for " + "PolicyQualifiers.");
+ }
+ while (val.data.available() != 0) {
+ DerValue pq = val.data.getDerValue();
+ PolicyQualifierInfo info = new PolicyQualifierInfo(pq);
+ add(info);
+ }
+ }
+
+ public void add(PolicyQualifierInfo info) {
+ mInfo.addElement(info);
+ }
+
+ public int size() {
+ return mInfo.size();
+ }
+
+ public PolicyQualifierInfo getInfoAt(int i) {
+ return mInfo.elementAt(i);
+ }
+
+ /**
+ * Returns a printable representation of the CertificatePolicyId.
+ */
+ public String toString() {
+ String s = "PolicyQualifiers: [";
+ for (int i = 0; i < mInfo.size(); i++) {
+ PolicyQualifierInfo pq = mInfo.elementAt(i);
+ s = s + pq.toString();
+ }
+ s = s + "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the PolicyQualifiers to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ for (int i = 0; i < mInfo.size(); i++) {
+ PolicyQualifierInfo pq = mInfo.elementAt(i);
+ pq.encode(tmp);
+ }
+
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/PrintableConverter.java b/base/util/src/netscape/security/x509/PrintableConverter.java
new file mode 100644
index 000000000..d63696d8f
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PrintableConverter.java
@@ -0,0 +1,114 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+
+import netscape.security.util.ASN1CharStrConvMap;
+import netscape.security.util.DerValue;
+
+/**
+ * A AVAValueConverter that converts a Printable String attribute to a DerValue
+ * and vice versa. An example an attribute that is a printable string is "C".
+ *
+ * @see ASN1CharStrConvMap
+ * @see AVAValueConverter
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public class PrintableConverter implements AVAValueConverter {
+ // public constructors.
+
+ public PrintableConverter() {
+ }
+
+ /**
+ * Converts a string with ASN.1 Printable characters to a DerValue.
+ *
+ * @param valueString a string with Printable characters.
+ *
+ * @return a DerValue.
+ *
+ * @exception IOException if a Printable encoder is not
+ * available for the conversion.
+ */
+ public DerValue getValue(String valueString)
+ throws IOException {
+ return getValue(valueString, null);
+ }
+
+ public DerValue getValue(String valueString, byte[] tags) throws IOException {
+ try {
+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(DerValue.tag_PrintableString);
+ if (encoder == null)
+ throw new IOException("No encoder for printable");
+
+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray());
+ ByteBuffer byteBuffer = encoder.encode(charBuffer);
+
+ return new DerValue(DerValue.tag_PrintableString,
+ byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit());
+
+ } catch (CharacterCodingException e) {
+ throw new IllegalArgumentException("Invalid Printable String AVA Value", e);
+ }
+ }
+
+ /**
+ * Converts a BER encoded value of PrintableString to a DER encoded value.
+ * Checks if the BER encoded value is a PrintableString.
+ * NOTE only DER encoded values are currently accepted on input.
+ *
+ * @param berStream A byte array of the BER encoded value.
+ *
+ * @return A DerValue.
+ *
+ * @exception IOException if the BER value cannot be converted to a
+ * PrintableString DER value.
+ */
+ public DerValue getValue(byte[] berStream)
+ throws IOException {
+ DerValue value = new DerValue(berStream);
+ if (value.tag != DerValue.tag_PrintableString)
+ throw new IOException("Invalid Printable String AVA Value");
+ return value;
+ }
+
+ /**
+ * Converts a DerValue of PrintableString to a java string with
+ * PrintableString characters.
+ *
+ * @param avaValue a DerValue.
+ *
+ * @return a string with PrintableString characters.
+ *
+ * @exception IOException if the DerValue is not a PrintableString i.e.
+ * The DerValue cannot be converted to a string
+ * with PrintableString characters.
+ */
+ public String getAsString(DerValue avaValue)
+ throws IOException {
+ return avaValue.getPrintableString();
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/PrivateKeyUsageExtension.java b/base/util/src/netscape/security/x509/PrivateKeyUsageExtension.java
new file mode 100644
index 000000000..e3ecdb33d
--- /dev/null
+++ b/base/util/src/netscape/security/x509/PrivateKeyUsageExtension.java
@@ -0,0 +1,339 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the Private Key Usage Extension.
+ *
+ * <p>
+ * The Private Key Usage Period extension allows the certificate issuer to specify a different validity period for the
+ * private key than the certificate. This extension is intended for use with digital signature keys. This extension
+ * consists of two optional components notBefore and notAfter. The private key associated with the certificate should
+ * not be used to sign objects before or after the times specified by the two components, respectively.
+ *
+ * <pre>
+ * PrivateKeyUsagePeriod ::= SEQUENCE {
+ * notBefore [0] GeneralizedTime OPTIONAL,
+ * notAfter [1] GeneralizedTime OPTIONAL }
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.12
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class PrivateKeyUsageExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7623695233957629936L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info.extensions.PrivateKeyUsage";
+ /**
+ * Sub attributes name for this CertAttrSet.
+ */
+ public static final String NAME = "PrivateKeyUsage";
+ public static final String NOT_BEFORE = "not_before";
+ public static final String NOT_AFTER = "not_after";
+
+ // Private data members
+ private static final byte TAG_BEFORE = 0;
+ private static final byte TAG_AFTER = 1;
+
+ private Date notBefore;
+ private Date notAfter;
+
+ // Encode this extension value.
+ private void encodeThis() throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+
+ DerOutputStream tagged = new DerOutputStream();
+ if (notBefore != null) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putGeneralizedTime(notBefore);
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_BEFORE), tmp);
+ }
+ if (notAfter != null) {
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.putGeneralizedTime(notAfter);
+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
+ false, TAG_AFTER), tmp);
+ }
+ seq.write(DerValue.tag_Sequence, tagged);
+ extensionValue = seq.toByteArray();
+ }
+
+ /**
+ * The default constructor for PrivateKeyUsageExtension.
+ *
+ * @param notBefore the date/time before which the private key
+ * should not be used.
+ * @param notAfter the date/time after which the private key
+ * should not be used.
+ */
+ public PrivateKeyUsageExtension(Date notBefore, Date notAfter)
+ throws IOException {
+ this.notBefore = notBefore;
+ this.notAfter = notAfter;
+
+ this.extensionId = PKIXExtensions.PrivateKeyUsage_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ *
+ * @exception CertificateException on certificate parsing errors.
+ * @exception IOException on error.
+ */
+ public PrivateKeyUsageExtension(Boolean critical, Object value)
+ throws CertificateException, IOException {
+ this.extensionId = PKIXExtensions.PrivateKeyUsage_Id;
+ this.critical = critical.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new CertificateException("Illegal argument type");
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerInputStream str = new DerInputStream(extValue);
+ DerValue[] seq = str.getSequence(2);
+
+ // NB. this is always encoded with the IMPLICIT tag
+ // The checks only make sense if we assume implicit tagging,
+ // with explicit tagging the form is always constructed.
+ for (int i = 0; i < seq.length; i++) {
+ DerValue opt = seq[i];
+
+ if (opt.isContextSpecific((byte) TAG_BEFORE) &&
+ !opt.isConstructed()) {
+ if (notBefore != null) {
+ throw new CertificateParsingException(
+ "Duplicate notBefore in PrivateKeyUsage.");
+ }
+ opt.resetTag(DerValue.tag_GeneralizedTime);
+ str = new DerInputStream(opt.toByteArray());
+ notBefore = str.getGeneralizedTime();
+
+ } else if (opt.isContextSpecific((byte) TAG_AFTER) &&
+ !opt.isConstructed()) {
+ if (notAfter != null) {
+ throw new CertificateParsingException(
+ "Duplicate notAfter in PrivateKeyUsage.");
+ }
+ opt.resetTag(DerValue.tag_GeneralizedTime);
+ str = new DerInputStream(opt.toByteArray());
+ notAfter = str.getGeneralizedTime();
+ } else
+ throw new IOException("Invalid encoding of " +
+ "PrivateKeyUsageExtension");
+ }
+ }
+
+ /**
+ * Return the printable string.
+ */
+ public String toString() {
+ return (super.toString() +
+ "PrivateKeyUsage: [From: " +
+ ((notBefore == null) ? "" : notBefore.toString()) +
+ ", To: " +
+ ((notAfter == null) ? "" : notAfter.toString()) + "]\n");
+ }
+
+ /**
+ * Return notBefore date
+ */
+ public Date getNotBefore() {
+ return (notBefore);
+ }
+
+ /**
+ * Return notAfter date
+ */
+ public Date getNotAfter() {
+ return (notAfter);
+ }
+
+ /**
+ * Verify that that the current time is within the validity period.
+ *
+ * @exception CertificateExpiredException if the certificate has expired.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid.
+ */
+ public void valid()
+ throws CertificateNotYetValidException, CertificateExpiredException {
+ Date now = new Date();
+ valid(now);
+ }
+
+ /**
+ * Verify that that the passed time is within the validity period.
+ *
+ * @exception CertificateExpiredException if the certificate has expired
+ * with respect to the <code>Date</code> supplied.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid with respect to the <code>Date</code> supplied.
+ *
+ */
+ public void valid(Date now)
+ throws CertificateNotYetValidException, CertificateExpiredException {
+ /*
+ * we use the internal Dates rather than the passed in Date
+ * because someone could override the Date methods after()
+ * and before() to do something entirely different.
+ */
+ if (notBefore.after(now)) {
+ throw new CertificateNotYetValidException("NotBefore: " +
+ notBefore.toString());
+ }
+ if (notAfter.before(now)) {
+ throw new CertificateExpiredException("NotAfter: " +
+ notAfter.toString());
+ }
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.PrivateKeyUsage_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception CertificateException on decoding errors.
+ */
+ public void decode(InputStream in) throws CertificateException {
+ throw new CertificateException("Method not to be called directly.");
+ }
+
+ /**
+ * Set the attribute value.
+ *
+ * @exception CertificateException on attribute handling errors.
+ */
+ public void set(String name, Object obj)
+ throws CertificateException {
+ clearValue();
+ if (!(obj instanceof Date)) {
+ throw new CertificateException("Attribute must be of type Date.");
+ }
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ notBefore = (Date) obj;
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ notAfter = (Date) obj;
+ } else {
+ throw new CertificateException("Attribute name not recognized by"
+ + " CertAttrSet:PrivateKeyUsage.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ *
+ * @exception CertificateException on attribute handling errors.
+ */
+ public Object get(String name) throws CertificateException {
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ return (new Date(notBefore.getTime()));
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ return (new Date(notAfter.getTime()));
+ } else {
+ throw new CertificateException("Attribute name not recognized by"
+ + " CertAttrSet:PrivateKeyUsage.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ *
+ * @exception CertificateException on attribute handling errors.
+ */
+ public void delete(String name) throws CertificateException {
+ if (name.equalsIgnoreCase(NOT_BEFORE)) {
+ notBefore = null;
+ } else if (name.equalsIgnoreCase(NOT_AFTER)) {
+ notAfter = null;
+ } else {
+ throw new CertificateException("Attribute name not recognized by"
+ + " CertAttrSet:PrivateKeyUsage.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NOT_BEFORE);
+ elements.addElement(NOT_AFTER);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/Qualifier.java b/base/util/src/netscape/security/x509/Qualifier.java
new file mode 100644
index 000000000..7c0c7edfe
--- /dev/null
+++ b/base/util/src/netscape/security/x509/Qualifier.java
@@ -0,0 +1,63 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Qualifier.
+ *
+ * Qualifier ::= CHOICE {
+ * cPRuri CPSuri,
+ * userNotice UserNotice
+ * }
+ *
+ * @author Thomas Kwan
+ */
+public class Qualifier implements java.io.Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2214531407387992974L;
+
+ /**
+ * Create a PolicyQualifierInfo
+ *
+ * @param id the ObjectIdentifier for the policy id.
+ */
+ public Qualifier() {
+ }
+
+ public Qualifier(DerValue val) throws IOException {
+ // needs to override this
+ }
+
+ /**
+ * Write the PolicyQualifier to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ // needs to override this
+ }
+}
diff --git a/base/util/src/netscape/security/x509/RDN.java b/base/util/src/netscape/security/x509/RDN.java
new file mode 100644
index 000000000..c5e8765a0
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RDN.java
@@ -0,0 +1,303 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * RDNs are a set of {attribute = value} assertions. Some of those
+ * attributes are "distinguished" (unique w/in context). Order is
+ * never relevant.
+ *
+ * Some X.500 names include only a single distinguished attribute
+ * per RDN. This style is currently common.
+ *
+ * Note that DER-encoded RDNs sort AVAs by assertion OID ... so that
+ * when we parse this data we don't have to worry about canonicalizing
+ * it, but we'll need to sort them when we expose the RDN class more.
+ *
+ * @see X500Name
+ * @see AVA
+ * @see LdapDNStrConverter
+ */
+
+public class RDN {
+ // public constructors
+
+ /**
+ * Constructs a RDN from a Ldap DN String with one RDN component
+ * using the global default LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @param rdnString a Ldap DN string with one RDN component, e.g. as
+ * defined in RFC1779.
+ * @exception IOException if error occurs while parsing the string.
+ */
+ public RDN(String rdnString)
+ throws IOException {
+ RDN rdn = LdapDNStrConverter.getDefault().parseRDN(rdnString);
+ assertion = rdn.getAssertion();
+ }
+
+ /**
+ * Like RDN(String) with a DER encoding order given as argument for
+ * Directory Strings.
+ */
+ public RDN(String rdnString, byte[] tags)
+ throws IOException {
+ RDN rdn = LdapDNStrConverter.getDefault().parseRDN(rdnString, tags);
+ assertion = rdn.getAssertion();
+ }
+
+ /**
+ * Constructs a RDN from a Ldap DN string with one RDN component
+ * using the specified Ldap DN Str converter.
+ * For example, RFC1779StrConverter can be passed to parse a Ldap
+ * DN string in RFC1779 format.
+ *
+ * @see LdapDNStrConverter
+ * @param rdnString Ldap DN string.
+ * @param ldapDNStrConverter a LdapDNStrConverter.
+ */
+ public RDN(String rdnString, LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ RDN rdn = ldapDNStrConverter.parseRDN(rdnString);
+ assertion = rdn.getAssertion();
+ }
+
+ /**
+ * Constructs a RDN from a DerValue.
+ *
+ * @param set Der value of a set of AVAs.
+ */
+ public RDN(DerValue set) throws IOException {
+ if (set.tag != DerValue.tag_Set)
+ throw new CertParseError("X500 RDN");
+
+ int j_max = 50; // XXX j_max = f(data)!!
+ int j;
+ int i;
+
+ AVA[] avas = new AVA[j_max];
+
+ // create a temporary array big enough for a huge set of AVA's
+ for (j = 0; j < j_max; j++) {
+ avas[j] = new AVA(set.data);
+ if (set.data.available() == 0)
+ break;
+ }
+
+ // copy the elements into it
+ if (j >= j_max - 1) {
+ assertion = new AVA[j + 1];
+ } else {
+ assertion = new AVA[j + 1];
+ for (i = 0; i < (j + 1); i++) {
+ assertion[i] = avas[i];
+ }
+ }
+
+ /*
+ if (set.data.available () != 0)
+ // throw new CertParseError ("X500 RDN 2");
+ System.out.println (" ... RDN parse, ignored bytes = "
+ + set.data.available ());
+ */
+ }
+
+ /**
+ * Constructs a RDN from a Der Input Stream.
+ *
+ * @param in a Der Input Stream.
+ */
+ public RDN(DerInputStream in) throws IOException {
+ /* an RDN is a SET of avas */
+ DerValue avaset[] = in.getSet(1);
+ int i;
+ assertion = new AVA[avaset.length];
+ for (i = 0; i < assertion.length; i++)
+ assertion[i] = new AVA(avaset[i].data);
+ }
+
+ /**
+ * Constructs a RDN from an array of AVA.
+ *
+ * @param avas a AVA Array.
+ */
+ public RDN(AVA avas[]) {
+ assertion = (AVA[]) avas.clone();
+ }
+
+ /**
+ * convenience method.
+ */
+ public RDN(Vector<AVA> avaVector) {
+ int size = avaVector.size();
+ assertion = new AVA[size];
+ for (int i = 0; i < size; i++) {
+ assertion[i] = avaVector.elementAt(i);
+ }
+ }
+
+ /**
+ * returns an array of AVA in the RDN.
+ *
+ * @return array of AVA in this RDN.
+ */
+ public AVA[] getAssertion() {
+ return (AVA[]) assertion.clone();
+ }
+
+ /**
+ * returns the number of AVAs in the RDN.
+ *
+ * @return number of AVAs in this RDN.
+ */
+ public int getAssertionLength() {
+ return assertion.length;
+ }
+
+ private AVA assertion[];
+
+ private class AVAEnumerator implements Enumeration<AVA> {
+ private int index;
+
+ public AVAEnumerator() {
+ index = 0;
+ }
+
+ public boolean hasMoreElements() {
+ return (index < assertion.length);
+ }
+
+ public AVA nextElement() {
+ if (index >= assertion.length)
+ return null;
+ return assertion[index++];
+ }
+ }
+
+ // other public methods.
+
+ /**
+ * Checks if this RDN is the same as another by comparing the AVAs
+ * in the RDNs.
+ *
+ * @param other the other RDN.
+ * @return true iff the other RDN is the same.
+ */
+ public boolean equals(RDN other) {
+ int i;
+
+ if (other == this)
+ return true;
+ if (assertion.length != other.assertion.length)
+ return false;
+
+ for (i = 0; i < assertion.length; i++)
+ if (!assertion[i].equals(other.assertion[i]))
+ return false;
+
+ return true;
+ }
+
+ DerValue findAttribute(ObjectIdentifier oid) {
+ int i;
+
+ for (i = 0; i < assertion.length; i++)
+ if (assertion[i].oid.equals(oid))
+ return assertion[i].value;
+ return null;
+ }
+
+ /**
+ * Encodes this RDN to a Der output stream.
+ *
+ * @param out the Der Output Stream.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ int i;
+
+ for (i = 0; i < assertion.length; i++)
+ assertion[i].encode(tmp);
+ out.write(DerValue.tag_Set, tmp);
+ }
+
+ /**
+ * returns an enumeration of AVAs that make up this RDN.
+ *
+ * @return an enumeration of AVAs that make up this RDN.
+ */
+ public Enumeration<AVA> getAVAs() {
+ return new AVAEnumerator();
+ }
+
+ /**
+ * Returns a Ldap DN string with one RDN component using the
+ * global default LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @return the Ldap DN String of this RDN.
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public String toLdapDNString()
+ throws IOException {
+ return LdapDNStrConverter.getDefault().encodeRDN(this);
+ }
+
+ /**
+ * Returns a Ldap DN String with this RDN component using the specified
+ * LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @param ldapDNStrConverter a LdapDNStrConverter.
+ * @return a Ldap DN String.
+ * @exception IOException if an error occurs in the conversion.
+ */
+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ return ldapDNStrConverter.encodeRDN(this);
+ }
+
+ /**
+ * Returns a Ldap DN string with this RDN component using the global
+ * default LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ * @return the Ldap DN String with this RDN component, null if an error
+ * occurs in the conversion.
+ */
+ public String toString() {
+ String s;
+ try {
+ s = toLdapDNString();
+ } catch (IOException e) {
+ return null;
+ }
+ return s;
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/RFC1779StrConverter.java b/base/util/src/netscape/security/x509/RFC1779StrConverter.java
new file mode 100644
index 000000000..6527d0fff
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RFC1779StrConverter.java
@@ -0,0 +1,102 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Converts a RFC 1779 string to a X500Name, RDN or AVA object and vice versa.
+ *
+ * @see LdapDNStrConverter
+ * @see LdapV3DNStrConverter
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ */
+
+public class RFC1779StrConverter extends LdapV3DNStrConverter {
+ //
+ // Constructors.
+ //
+
+ /**
+ * Constructs a RFC1779StrConverter using the global default
+ * X500NameAttrMap and accepts OIDs not listed in the attribute map.
+ */
+ public RFC1779StrConverter() {
+ super();
+ }
+
+ /**
+ * Constructs a RFC1779StrConverter using the specified X500NameAttrMap
+ * and boolean for whether to accept OIDs not in the X500NameAttrMap.
+ *
+ * @param attributeMap A X500NameAttrMap to use for this converter.
+ * @param doAcceptUnknownOids Accept unregistered attributes, i.e. OIDs
+ * not in the map).
+ */
+ public RFC1779StrConverter(X500NameAttrMap attributeMap,
+ boolean doAcceptUnknownOids) {
+ super(attributeMap, doAcceptUnknownOids);
+ }
+
+ //
+ // overriding methods.
+ //
+
+ /**
+ * Converts a OID to a attribute keyword in a Ldap DN string or
+ * to a "OID.1.2.3.4" string syntax as defined in RFC1779.
+ *
+ * @param oid an ObjectIdentifier.
+ *
+ * @return a attribute keyword or "OID.1.2.3.4" string.
+ *
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public String encodeOID(ObjectIdentifier oid)
+ throws IOException {
+ String keyword = attrMap.getName(oid);
+ if (keyword == null)
+ if (!acceptUnknownOids)
+ throw new IllegalArgumentException("Unrecognized OID");
+ else
+ keyword = "OID" + "." + oid.toString();
+ return keyword;
+ }
+
+ /**
+ * Converts a attribute value as a DerValue to a string in a
+ * RFC1779 Ldap DN string.
+ *
+ * @param attrValue an attribute value.
+ * @param oid ObjectIdentifier for the attribute.
+ * @return a string in RFC1779 syntax.
+ * @exception IOException if an error occurs during the conversion.
+ */
+ public String encodeValue(DerValue attrValue, ObjectIdentifier oid)
+ throws IOException {
+ String s = super.encodeValue(attrValue, oid);
+ if (s.indexOf('\n') != -1)
+ return "\"" + s + "\"";
+ else
+ return s;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/RFC822Name.java b/base/util/src/netscape/security/x509/RFC822Name.java
new file mode 100644
index 000000000..257b5c51d
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RFC822Name.java
@@ -0,0 +1,85 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the RFC822Name as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.3
+ * @see GeneralName
+ * @see GeneralNames
+ * @see GeneralNameInterface
+ */
+public class RFC822Name implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1453025303548809007L;
+ private String name;
+
+ /**
+ * Create the RFC822Name object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER RFC822Name.
+ * @exception IOException on error.
+ */
+ public RFC822Name(DerValue derValue) throws IOException {
+ name = derValue.getIA5String();
+ }
+
+ /**
+ * Create the RFC822Name object with the specified name.
+ *
+ * @param name the RFC822Name.
+ */
+ public RFC822Name(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_RFC822);
+ }
+
+ /**
+ * Encode the RFC822 name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the RFC822Name to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putIA5String(name);
+ }
+
+ /**
+ * Convert the name into user readable string.
+ */
+ public String toString() {
+ return ("RFC822Name: " + name);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/ReasonFlags.java b/base/util/src/netscape/security/x509/ReasonFlags.java
new file mode 100755
index 000000000..e43c7022c
--- /dev/null
+++ b/base/util/src/netscape/security/x509/ReasonFlags.java
@@ -0,0 +1,283 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the CRL Reason Flags.
+ *
+ * <p>
+ * This extension, if present, defines the identifies the reason for the certificate revocation.
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.3
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class ReasonFlags {
+
+ /**
+ * Reasons
+ */
+ public static final String UNUSED = "unused";
+ public static final String KEY_COMPROMISE = "key_compromise";
+ public static final String CA_COMPROMISE = "ca_compromise";
+ public static final String AFFLIATION_CHANGED = "affliation_changed";
+ public static final String SUPERSEDED = "superseded";
+ public static final String CESSATION_OF_OPERATION = "cessation_of_operation";
+ public static final String CERTIFICATION_HOLD = "certification_hold";
+ public static final String PRIVILEGE_WITHDRAWN = "privilege_withdrawn";
+ public static final String AA_COMPROMISE = "aa_compromise";
+
+ // Private data members
+ private boolean[] bitString;
+
+ /**
+ * Check if bit is set.
+ *
+ * @param position the position in the bit string to check.
+ */
+ private boolean isSet(int position) {
+ return bitString[position];
+ }
+
+ /**
+ * Set the bit at the specified position.
+ */
+ private void set(int position, boolean val) {
+ // enlarge bitString if necessary
+ if (position >= bitString.length) {
+ boolean[] tmp = new boolean[position + 1];
+ System.arraycopy(bitString, 0, tmp, 0, bitString.length);
+ bitString = tmp;
+ }
+ bitString[position] = val;
+ }
+
+ /**
+ * Create a ReasonFlags with the passed bit settings.
+ *
+ * @param reasons the bits to be set for the ReasonFlags.
+ */
+ public ReasonFlags(byte[] reasons) {
+ bitString = new BitArray(reasons.length * 8, reasons).toBooleanArray();
+ }
+
+ /**
+ * Create a ReasonFlags with the passed bit settings.
+ *
+ * @param reasons the bits to be set for the ReasonFlags.
+ */
+ public ReasonFlags(boolean[] reasons) {
+ this.bitString = reasons;
+ }
+
+ /**
+ * Create a ReasonFlags with the passed bit settings.
+ *
+ * @param reasons the bits to be set for the ReasonFlags.
+ */
+ public ReasonFlags(BitArray reasons) {
+ this.bitString = reasons.toBooleanArray();
+ }
+
+ /**
+ * Create the object from the passed DER encoded value.
+ *
+ * @param in the DerInputStream to read the ReasonFlags from.
+ * @exception IOException on decoding errors.
+ */
+ public ReasonFlags(DerInputStream in) throws IOException {
+ DerValue derVal = in.getDerValue();
+ this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
+ }
+
+ /**
+ * Create the object from the passed DER encoded value.
+ *
+ * @param derVal the DerValue decoded from the stream.
+ * @exception IOException on decoding errors.
+ */
+ public ReasonFlags(DerValue derVal) throws IOException {
+ this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ if (!(obj instanceof Boolean)) {
+ throw new IOException("Attribute must be of type Boolean.");
+ }
+ boolean val = ((Boolean) obj).booleanValue();
+ if (name.equalsIgnoreCase(UNUSED)) {
+ set(0, val);
+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) {
+ set(1, val);
+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) {
+ set(2, val);
+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) {
+ set(3, val);
+ } else if (name.equalsIgnoreCase(SUPERSEDED)) {
+ set(4, val);
+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) {
+ set(5, val);
+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) {
+ set(6, val);
+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) {
+ set(7, val);
+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) {
+ set(8, val);
+ } else {
+ throw new IOException("Name not recognized by ReasonFlags");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(UNUSED)) {
+ return new Boolean(isSet(0));
+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) {
+ return new Boolean(isSet(1));
+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) {
+ return new Boolean(isSet(2));
+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) {
+ return new Boolean(isSet(3));
+ } else if (name.equalsIgnoreCase(SUPERSEDED)) {
+ return new Boolean(isSet(4));
+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) {
+ return new Boolean(isSet(5));
+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) {
+ return new Boolean(isSet(6));
+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) {
+ return new Boolean(isSet(7));
+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) {
+ return new Boolean(isSet(8));
+ } else {
+ throw new IOException("Name not recognized by ReasonFlags");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(UNUSED)) {
+ set(0, false);
+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) {
+ set(1, false);
+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) {
+ set(2, false);
+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) {
+ set(3, false);
+ } else if (name.equalsIgnoreCase(SUPERSEDED)) {
+ set(4, false);
+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) {
+ set(5, false);
+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) {
+ set(6, false);
+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) {
+ set(7, false);
+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) {
+ set(8, false);
+ } else {
+ throw new IOException("Name not recognized by ReasonFlags");
+ }
+ }
+
+ /**
+ * Returns a printable representation of the ReasonFlags.
+ */
+ public String toString() {
+ String s = super.toString() + "Reason Flags [\n";
+
+ try {
+ if (isSet(0)) {
+ s += " Unused\n";
+ }
+ if (isSet(1)) {
+ s += " Key Compromise\n";
+ }
+ if (isSet(2)) {
+ s += " CA_Compromise\n";
+ }
+ if (isSet(3)) {
+ s += " Affiliation_Changed\n";
+ }
+ if (isSet(4)) {
+ s += " Superseded\n";
+ }
+ if (isSet(5)) {
+ s += " Cessation Of Operation\n";
+ }
+ if (isSet(6)) {
+ s += " Certificate Hold\n";
+ }
+ if (isSet(7)) {
+ s += " Privilege Withdrawn\n";
+ }
+ if (isSet(8)) {
+ s += " AA Compromise\n";
+ }
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ }
+
+ s += "]\n";
+
+ return (s);
+ }
+
+ /**
+ * Write the extension to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putUnalignedBitString(new BitArray(this.bitString));
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getElements() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(UNUSED);
+ elements.addElement(KEY_COMPROMISE);
+ elements.addElement(CA_COMPROMISE);
+ elements.addElement(AFFLIATION_CHANGED);
+ elements.addElement(SUPERSEDED);
+ elements.addElement(CESSATION_OF_OPERATION);
+ elements.addElement(CERTIFICATION_HOLD);
+ elements.addElement(PRIVILEGE_WITHDRAWN);
+ elements.addElement(AA_COMPROMISE);
+
+ return (elements.elements());
+ }
+}
diff --git a/base/util/src/netscape/security/x509/RevocationReason.java b/base/util/src/netscape/security/x509/RevocationReason.java
new file mode 100644
index 000000000..419eb1772
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RevocationReason.java
@@ -0,0 +1,119 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+/**
+ * Represent the enumerated type used in CRLReason Extension of CRL entry.
+ *
+ *
+ * @author galperin
+ * @version $Revision$, $Date$
+ */
+
+public final class RevocationReason {
+ /**
+ * Reasons
+ */
+ public static final RevocationReason UNSPECIFIED = new RevocationReason(0);
+ public static final RevocationReason KEY_COMPROMISE = new RevocationReason(1);
+ public static final RevocationReason CA_COMPROMISE = new RevocationReason(2);
+ public static final RevocationReason AFFILIATION_CHANGED = new RevocationReason(3);
+ public static final RevocationReason SUPERSEDED = new RevocationReason(4);
+ public static final RevocationReason CESSATION_OF_OPERATION = new RevocationReason(5);
+ public static final RevocationReason CERTIFICATE_HOLD = new RevocationReason(6);
+ public static final RevocationReason REMOVE_FROM_CRL = new RevocationReason(8);
+ public static final RevocationReason PRIVILEGE_WITHDRAWN = new RevocationReason(9);
+ public static final RevocationReason AA_COMPROMISE = new RevocationReason(10);
+
+ // Private data members
+ private int mReason;
+
+ /**
+ * Create a RevocationReason with the passed integer value.
+ *
+ * @param reason integer value of the enumeration alternative.
+ */
+ private RevocationReason(int reason) {
+ this.mReason = reason;
+ }
+
+ public int toInt() {
+ return mReason;
+ }
+
+ public static RevocationReason fromInt(int reason) {
+ if (reason == UNSPECIFIED.mReason)
+ return UNSPECIFIED;
+ if (reason == KEY_COMPROMISE.mReason)
+ return KEY_COMPROMISE;
+ if (reason == CA_COMPROMISE.mReason)
+ return CA_COMPROMISE;
+ if (reason == AFFILIATION_CHANGED.mReason)
+ return AFFILIATION_CHANGED;
+ if (reason == SUPERSEDED.mReason)
+ return SUPERSEDED;
+ if (reason == CESSATION_OF_OPERATION.mReason)
+ return CESSATION_OF_OPERATION;
+ if (reason == CERTIFICATE_HOLD.mReason)
+ return CERTIFICATE_HOLD;
+ if (reason == REMOVE_FROM_CRL.mReason)
+ return REMOVE_FROM_CRL;
+ if (reason == PRIVILEGE_WITHDRAWN.mReason)
+ return PRIVILEGE_WITHDRAWN;
+ if (reason == AA_COMPROMISE.mReason)
+ return AA_COMPROMISE;
+ return null;
+ }
+
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ else if (other instanceof RevocationReason)
+ return ((RevocationReason) other).mReason == mReason;
+ else
+ return false;
+ }
+
+ public int hashCode() {
+ return mReason;
+ }
+
+ public String toString() {
+ if (equals(UNSPECIFIED))
+ return "Unspecified";
+ if (equals(KEY_COMPROMISE))
+ return "Key_Compromise";
+ if (equals(CA_COMPROMISE))
+ return "CA_Compromise";
+ if (equals(AFFILIATION_CHANGED))
+ return "Affiliation_Changed";
+ if (equals(SUPERSEDED))
+ return "Superseded";
+ if (equals(CESSATION_OF_OPERATION))
+ return "Cessation_of_Operation";
+ if (equals(CERTIFICATE_HOLD))
+ return "Certificate_Hold";
+ if (equals(REMOVE_FROM_CRL))
+ return "Remove_from_CRL";
+ if (equals(PRIVILEGE_WITHDRAWN))
+ return "Privilege_Withdrawn";
+ if (equals(AA_COMPROMISE))
+ return "AA_Compromise";
+ return "[UNDEFINED]";
+ }
+}
diff --git a/base/util/src/netscape/security/x509/RevokedCertImpl.java b/base/util/src/netscape/security/x509/RevokedCertImpl.java
new file mode 100755
index 000000000..345694fb1
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RevokedCertImpl.java
@@ -0,0 +1,454 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * <p>
+ * Abstract class for a revoked certificate in a CRL. This class is for each entry in the
+ * <code>revokedCertificates</code>, so it deals with the inner <em>SEQUENCE</em>. The ASN.1 definition for this is:
+ *
+ * <pre>
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate ChoiceOfTime,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, must be v2
+ * } OPTIONAL
+ *
+ * CertificateSerialNumber ::= INTEGER
+ *
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnId OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * -- contains a DER encoding of a value
+ * -- of the type registered for use with
+ * -- the extnId object identifier value
+ * }
+ * </pre>
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.6 97/12/10
+ */
+
+public class RevokedCertImpl extends RevokedCertificate implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3449642360223397701L;
+
+ private SerialNumber serialNumber;
+ private Date revocationDate;
+ private CRLExtensions extensions = null;
+ private byte[] revokedCert;
+ private final static boolean isExplicit = false;
+
+ /**
+ * Default constructor.
+ */
+ public RevokedCertImpl() {
+ }
+
+ /**
+ * Constructs a revoked certificate entry using the serial number and
+ * revocation date.
+ *
+ * @param num
+ * the serial number of the revoked certificate.
+ * @param date
+ * the Date on which revocation took place.
+ */
+ public RevokedCertImpl(BigInteger num, Date date) {
+ this.serialNumber = new SerialNumber(num);
+ this.revocationDate = date;
+ }
+
+ /**
+ * Constructs a revoked certificate entry using the serial number,
+ * revocation date and the entry extensions.
+ *
+ * @param num
+ * the serial number of the revoked certificate.
+ * @param date
+ * the Date on which revocation took place.
+ * @param crlEntryExts
+ * the extensions for this entry.
+ */
+ public RevokedCertImpl(BigInteger num, Date date, CRLExtensions crlEntryExts) {
+ this.serialNumber = new SerialNumber(num);
+ this.revocationDate = date;
+ this.extensions = crlEntryExts;
+ }
+
+ public byte[] getEncoded() throws CRLException {
+ // XXX NOT IMPLEMENTED
+ if (revokedCert == null) {
+ DerOutputStream os = new DerOutputStream();
+ try {
+ encode(os);
+ } catch (Exception e) {
+ // revokedCert = null;
+ }
+ revokedCert = os.toByteArray();
+ }
+ return revokedCert;
+ }
+
+ public boolean hasUnsupportedCriticalExtension() {
+ // XXX NOT IMPLEMENTED
+ return true;
+ }
+
+ /**
+ * Sets extensions for this impl.
+ *
+ * @param crlEntryExts
+ * CRLExtensions
+ */
+ public void setExtensions(CRLExtensions crlEntryExts) {
+ this.extensions = crlEntryExts;
+ }
+
+ /**
+ * Unmarshals a revoked certificate from its encoded form.
+ *
+ * @param revokedCert
+ * the encoded bytes.
+ * @exception CRLException
+ * on parsing errors.
+ * @exception X509ExtensionException
+ * on extension handling errors.
+ */
+ public RevokedCertImpl(byte[] revokedCert) throws CRLException,
+ X509ExtensionException {
+ try {
+ DerValue derValue = new DerValue(revokedCert);
+ parse(derValue);
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.toString());
+ }
+ }
+
+ /**
+ * Unmarshals a revoked certificate from its encoded form.
+ *
+ * @param derValue
+ * the DER value containing the revoked certificate.
+ * @exception CRLException
+ * on parsing errors.
+ * @exception X509ExtensionException
+ * on extension handling errors.
+ */
+ public RevokedCertImpl(DerValue derValue) throws CRLException,
+ X509ExtensionException {
+ parse(derValue);
+ }
+
+ /**
+ * Returns true if this revoked certificate entry has extensions, otherwise
+ * false.
+ *
+ * @return true if this CRL entry has extensions, otherwise false.
+ */
+ public boolean hasExtensions() {
+ if (extensions == null)
+ return false;
+ else
+ return true;
+ }
+
+ /**
+ * Decode a revoked certificate from an input stream.
+ *
+ * @param inStrm
+ * an input stream holding at least one revoked certificate
+ * @exception CRLException
+ * on parsing errors.
+ * @exception X509ExtensionException
+ * on extension handling errors.
+ */
+ public void decode(InputStream inStrm) throws CRLException,
+ X509ExtensionException {
+ try {
+ DerValue derValue = new DerValue(inStrm);
+ parse(derValue);
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.toString());
+ }
+ }
+
+ /**
+ * Encodes the revoked certificate to an output stream.
+ *
+ * @param outStrm
+ * an output stream to which the encoded revoked certificate is
+ * written.
+ * @exception CRLException
+ * on encoding errors.
+ * @exception X509ExtensionException
+ * on extension handling errors.
+ */
+ public void encode(DerOutputStream outStrm) throws CRLException,
+ X509ExtensionException {
+ try {
+ if (revokedCert == null) {
+ DerOutputStream tmp = new DerOutputStream();
+ // sequence { serialNumber, revocationDate, extensions }
+ serialNumber.encode(tmp);
+
+ // from 2050 should encode GeneralizedTime
+ tmp.putUTCTime(revocationDate);
+
+ if (extensions != null)
+ extensions.encode(tmp, isExplicit);
+
+ DerOutputStream seq = new DerOutputStream();
+ seq.write(DerValue.tag_Sequence, tmp);
+
+ revokedCert = seq.toByteArray();
+ }
+ outStrm.write(revokedCert);
+ } catch (IOException e) {
+ throw new CRLException("Encoding error: " + e.toString());
+ }
+ }
+
+ /**
+ * Gets the serial number for this RevokedCertificate, the <em>userCertificate</em>.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber() {
+ return ((BigInt) serialNumber.getNumber()).toBigInteger();
+ }
+
+ /**
+ * Gets the revocation date for this RevokedCertificate, the <em>revocationDate</em>.
+ *
+ * @return the revocation date.
+ */
+ public Date getRevocationDate() {
+ return (new Date(revocationDate.getTime()));
+ }
+
+ /**
+ * Returns extensions for this impl.
+ *
+ * @return the CRLExtensions
+ */
+ public CRLExtensions getExtensions() {
+ return extensions;
+ }
+
+ /**
+ * Returns a printable string of this revoked certificate.
+ *
+ * @return value of this revoked certificate in a printable form.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(serialNumber.toString());
+ sb.append(" On: " + revocationDate.toString());
+ if (extensions != null) {
+ sb.append("\n");
+ for (int i = 0; i < extensions.size(); i++)
+ sb.append("Entry Extension[" + i + "]: "
+ + ((Extension) (extensions.elementAt(i))).toString());
+ }
+ sb.append("\n");
+ return (sb.toString());
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked CRITICAL in the
+ * RevokedCertificate by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * Object that are marked critical.
+ */
+ public Set<String> getCriticalExtensionOIDs() {
+ if (extensions == null)
+ return null;
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (ex.isCritical())
+ extSet.add(ex.getExtensionId().toString());
+ }
+ return extSet;
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked NON-CRITICAL in the
+ * RevokedCertificate by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * Object that are marked critical.
+ */
+ public Set<String> getNonCriticalExtensionOIDs() {
+ if (extensions == null)
+ return null;
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (!ex.isCritical())
+ extSet.add(ex.getExtensionId().toString());
+ }
+ return extSet;
+ }
+
+ /**
+ * Gets the DER encoded OCTET string for the extension value
+ * (<em>extnValue</em>) identified by the passed in oid String.
+ * The <code>oid</code> string is
+ * represented by a set of positive whole number separated
+ * by ".", that means,<br>
+ * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;positive
+ * whole number&gt;.&lt;...&gt;
+ *
+ * @param oid the Object Identifier value for the extension.
+ * @return the DER encoded octet string of the extension value.
+ */
+ public byte[] getExtensionValue(String oid) {
+ if (extensions == null)
+ return null;
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
+ Extension crlExt = null;
+
+ if (extAlias == null) { // may be unknown
+ ObjectIdentifier findOID = new ObjectIdentifier(oid);
+ Extension ex = null;
+ ObjectIdentifier inCertOID;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ inCertOID = ex.getExtensionId();
+ if (inCertOID.equals(findOID)) {
+ crlExt = ex;
+ break;
+ }
+ }
+ } else
+ crlExt = extensions.get(extAlias);
+ if (crlExt == null)
+ return null;
+ byte[] extData = crlExt.getExtensionValue();
+ if (extData == null)
+ return null;
+
+ DerOutputStream out = new DerOutputStream();
+ out.putOctetString(extData);
+ return out.toByteArray();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private void parse(DerValue derVal)
+ throws CRLException, X509ExtensionException {
+
+ if (derVal.tag != DerValue.tag_Sequence) {
+ throw new CRLException("Invalid encoded RevokedCertificate, " +
+ "starting sequence tag missing.");
+ }
+ if (derVal.data.available() == 0)
+ throw new CRLException("No data encoded for RevokedCertificates");
+
+ // serial number
+ try {
+ DerInputStream in = derVal.toDerInputStream();
+ DerValue val = in.getDerValue();
+ this.serialNumber = new SerialNumber(val);
+ } catch (IOException e) {
+ throw new CRLException("Parsing Serial Number error: "
+ + e.toString());
+ }
+
+ // revocationDate
+ try {
+ int nextByte = derVal.data.peekByte();
+ if ((byte) nextByte == DerValue.tag_UtcTime) {
+ this.revocationDate = derVal.data.getUTCTime();
+ } else if ((byte) nextByte == DerValue.tag_GeneralizedTime) {
+ this.revocationDate = derVal.data.getGeneralizedTime();
+ } else {
+ throw new CRLException("Invalid encoding for RevokedCertificates");
+ }
+ } catch (IOException e) {
+ throw new CRLException("Parsing Revocation Date error: "
+ + e.toString());
+ }
+
+ if (derVal.data.available() == 0)
+ return; // no extensions
+
+ // crlEntryExtensions
+ try {
+ this.extensions = new CRLExtensions(derVal.toDerInputStream());
+ } catch (IOException e) {
+ throw new CRLException("Parsing CRL Entry Extensions error: "
+ + e.toString());
+ }
+ }
+
+ /**
+ * Serialization write ... X.509 certificates serialize as themselves, and
+ * they're parsed when they get read back. (Actually they serialize as some
+ * type data from the serialization subsystem, then the cert data.)
+ */
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws CRLException, X509ExtensionException, IOException {
+ DerOutputStream dos = new DerOutputStream();
+ encode(dos);
+ dos.derEncode(stream);
+ }
+
+ /**
+ * Serialization read ... X.509 certificates serialize as themselves, and
+ * they're parsed when they get read back.
+ */
+ private synchronized void readObject(ObjectInputStream stream)
+ throws CRLException, X509ExtensionException, IOException {
+ decode(stream);
+ }
+
+}
diff --git a/base/util/src/netscape/security/x509/RevokedCertificate.java b/base/util/src/netscape/security/x509/RevokedCertificate.java
new file mode 100644
index 000000000..2087d064a
--- /dev/null
+++ b/base/util/src/netscape/security/x509/RevokedCertificate.java
@@ -0,0 +1,95 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.math.BigInteger;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+
+/**
+ * <p>
+ * Abstract class for a revoked certificate in a CRL (Certificate Revocation List).
+ *
+ * The ASN.1 definition for <em>revokedCertificates</em> is:
+ *
+ * <pre>
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate ChoiceOfTime,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, must be v2
+ * } OPTIONAL
+ * <p>
+ * CertificateSerialNumber ::= INTEGER
+ * <p>
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ * <p>
+ * Extension ::= SEQUENCE {
+ * extnId OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * -- contains a DER encoding of a value
+ * -- of the type registered for use with
+ * -- the extnId object identifier value
+ * }
+ * </pre>
+ *
+ * @see X509CRL
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.4 97/12/10
+ */
+
+public abstract class RevokedCertificate extends X509CRLEntry {
+ /* implements X509Extension { */
+
+ /**
+ * Gets the serial number for this RevokedCertificate,
+ * the <em>userCertificate</em>.
+ *
+ * @return the serial number.
+ */
+ public abstract BigInteger getSerialNumber();
+
+ /**
+ * Gets the revocation date for this RevokedCertificate,
+ * the <em>revocationDate</em>.
+ *
+ * @return the revocation date.
+ */
+ public abstract Date getRevocationDate();
+
+ /**
+ * Returns true if this revoked certificate entry has
+ * extensions.
+ *
+ * @return true if this entry has extensions, false otherwise.
+ */
+ public abstract boolean hasExtensions();
+
+ /**
+ * Returns a string representation of this revoked certificate.
+ *
+ * @return a string representation of this revoked certificate.
+ */
+ public abstract String toString();
+
+ public abstract CRLExtensions getExtensions();
+
+}
diff --git a/base/util/src/netscape/security/x509/SerialNumber.java b/base/util/src/netscape/security/x509/SerialNumber.java
new file mode 100644
index 000000000..a2d7109c0
--- /dev/null
+++ b/base/util/src/netscape/security/x509/SerialNumber.java
@@ -0,0 +1,124 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the SerialNumber class used by certificates.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.5
+ */
+public class SerialNumber {
+ private BigInt serialNum;
+
+ // Construct the class from the DerValue
+ private void construct(DerValue derVal) throws IOException {
+ serialNum = derVal.getInteger();
+ if (derVal.data.available() != 0) {
+ throw new IOException("Excess SerialNumber data");
+ }
+ }
+
+ /**
+ * The default constructor for this class using BigInteger.
+ *
+ * @param num the BigInteger number used to create the serial number.
+ */
+ public SerialNumber(BigInteger num) {
+ serialNum = new BigInt(num);
+ }
+
+ public SerialNumber(BigInt num) {
+ serialNum = num;
+ }
+
+ /**
+ * The default constructor for this class using int.
+ *
+ * @param num the BigInteger number used to create the serial number.
+ */
+ public SerialNumber(int num) {
+ serialNum = new BigInt(num);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the SerialNumber from.
+ * @exception IOException on decoding errors.
+ */
+ public SerialNumber(DerInputStream in) throws IOException {
+ DerValue derVal = in.getDerValue();
+ construct(derVal);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DerValue.
+ *
+ * @param val the DerValue to read the SerialNumber from.
+ * @exception IOException on decoding errors.
+ */
+ public SerialNumber(DerValue val) throws IOException {
+ construct(val);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed stream.
+ *
+ * @param in the InputStream to read the SerialNumber from.
+ * @exception IOException on decoding errors.
+ */
+ public SerialNumber(InputStream in) throws IOException {
+ DerValue derVal = new DerValue(in);
+ construct(derVal);
+ }
+
+ /**
+ * Return the SerialNumber as user readable string.
+ */
+ public String toString() {
+ return ("SerialNumber: [" + serialNum.toString() + "]");
+ }
+
+ /**
+ * Encode the SerialNumber in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putInteger(serialNum);
+ }
+
+ /**
+ * Return the serial number.
+ */
+ public BigInt getNumber() {
+ return (serialNum);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java b/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java
new file mode 100644
index 000000000..c30ae1576
--- /dev/null
+++ b/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java
@@ -0,0 +1,242 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This represents the Subject Alternative Name Extension.
+ *
+ * This extension, if present, allows the subject to specify multiple
+ * alternative names.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ * <p>
+ * The ASN.1 syntax for this is:
+ *
+ * <pre>
+ * SubjectAltName ::= GeneralNames
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ * </pre>
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.9
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class SubjectAlternativeNameExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4022446008355607196L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT =
+ "x509.info.extensions.SubjectAlternativeName";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "SubjectAlternativeName";
+ public static final String SUBJECT_NAME = "subject_name";
+
+ // private data members
+ GeneralNames names;
+
+ // Encode this extension
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ try {
+ names.encode(os);
+ } catch (GeneralNamesException e) {
+ throw new IOException("SubjectAlternativeName: " + e);
+ }
+ extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a SubjectAlternativeNameExtension with the passed GeneralNames.
+ *
+ * @param names the GeneralNames for the subject.
+ * @exception IOException on error.
+ */
+ public SubjectAlternativeNameExtension(boolean critical, GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ public SubjectAlternativeNameExtension(GeneralNames names)
+ throws IOException {
+ this.names = names;
+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create a default SubjectAlternativeNameExtension.
+ */
+ public SubjectAlternativeNameExtension() {
+ extensionId = PKIXExtensions.SubjectAlternativeName_Id;
+ critical = false;
+ names = new GeneralNames();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public SubjectAlternativeNameExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id;
+ this.critical = critical.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new IOException("SubjectAlternativeName: "
+ + "Illegal argument type");
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ try {
+ names = new GeneralNames(val);
+ } catch (GeneralNamesException e) {
+ throw new IOException("SubjectAlternativeName: " + e);
+ }
+ }
+
+ /**
+ * Returns a printable representation of the SubjectAlternativeName.
+ */
+ public String toString() {
+ if (names == null)
+ return "";
+ String s = super.toString() + "SubjectAlternativeName [\n"
+ + names.toString() + "]\n";
+ return (s);
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.SubjectAlternativeName_Id;
+ //critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(SUBJECT_NAME)) {
+ if (!(obj instanceof GeneralNames)) {
+ throw new IOException("Attribute value should be of " +
+ "type GeneralNames.");
+ }
+ names = (GeneralNames) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectAlternativeName.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(SUBJECT_NAME)) {
+ return (names);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectAlternativeName.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(SUBJECT_NAME)) {
+ names = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectAlternativeName.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(SUBJECT_NAME);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/SubjectDirAttributesExtension.java b/base/util/src/netscape/security/x509/SubjectDirAttributesExtension.java
new file mode 100644
index 000000000..b249ef600
--- /dev/null
+++ b/base/util/src/netscape/security/x509/SubjectDirAttributesExtension.java
@@ -0,0 +1,286 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class represents the Subject Directory Attributes Extension.
+ *
+ * <p>
+ * The subject directory attributes extension is not recommended as an essential part of this profile, but it may be
+ * used in local environments. This extension MUST be non-critical.
+ *
+ * <pre>
+ * The ASN.1 syntax for this extension is:
+ *
+ * SubjectDirectoryAttributes ::= SEQUENCE (1..MAX) OF Attribute
+ *
+ * Attribute ::= SEQUENCE {
+ * type AttributeType,
+ * value SET OF AttributeValue
+ * -- at least one value is required --}
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY
+ *
+ * </pre>
+ *
+ * @author Christine Ho
+ * @version 1.7
+ *
+ * @see CertAttrSet
+ * @see Extension
+ */
+public class SubjectDirAttributesExtension extends Extension
+ implements CertAttrSet {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1215458115428197688L;
+
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ //public static final String IDENT = "x509.info.extensions.SubjectDirectoryAttributes";
+ public static final String IDENT = "Subject Directory Attributes";
+
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "SubjectDirectoryAttributes";
+
+ // Private data members
+ private Vector<Attribute> attrList = new Vector<Attribute>();
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ //encoding the attributes
+ Enumeration<Attribute> attrs = attrList.elements();
+ while (attrs.hasMoreElements()) {
+ Attribute attr = attrs.nextElement();
+ attr.encode(tmp);
+ }
+
+ out.write(DerValue.tag_SequenceOf, tmp);
+ this.extensionValue = out.toByteArray();
+ }
+
+ // Decode this extension value
+ private void decodeThis(DerValue derVal) throws IOException {
+
+ if (derVal.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for " +
+ "Subject Directory Attribute extension.");
+ }
+
+ if (derVal.data.available() == 0) {
+ throw new IOException(NAME + " No data available in "
+ + "passed DER encoded value.");
+ }
+
+ // Decode all the Attributes
+ while (derVal.data.available() != 0) {
+ DerValue encAttr = derVal.data.getDerValue();
+ Attribute attr = new Attribute(encAttr);
+ attrList.addElement(attr);
+ }
+ }
+
+ /**
+ * Default constructor for this object.
+ *
+ * @param derVal Der encoded value of this extension
+ */
+ public SubjectDirAttributesExtension(DerValue derVal) throws IOException {
+
+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id;
+ this.critical = false;
+ decodeThis(derVal);
+ }
+
+ /**
+ * Default constructor for this object.
+ *
+ * @param list Attribute object list
+ */
+ public SubjectDirAttributesExtension(Attribute[] list) throws IOException {
+
+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id;
+ this.critical = false;
+
+ if ((list == null) || (list.length == 0)) {
+ throw new IOException("No data available in "
+ + "passed Attribute List.");
+ }
+
+ // add the Attributes
+ for (int i = 0; i < list.length; i++) {
+ attrList.addElement(list[i]);
+ }
+ }
+
+ /**
+ * Constructor from parsing extension
+ *
+ * @param list Attribute object list
+ */
+ public SubjectDirAttributesExtension(Boolean crit, Object value)
+ throws IOException {
+
+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id;
+ this.critical = crit.booleanValue();
+
+ if (!(value instanceof byte[]))
+ throw new IOException(NAME + "Illegal argument type");
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ System.arraycopy(value, 0, extValue, 0, len);
+
+ this.extensionValue = extValue;
+ decodeThis(new DerValue(extValue));
+ }
+
+ /**
+ * Constructor for this object.
+ *
+ * @param list Attribute object list
+ * @param critical The criticality
+ */
+ public SubjectDirAttributesExtension(Attribute[] list, boolean critical)
+ throws IOException {
+
+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id;
+ this.critical = critical;
+
+ if ((list == null) || (list.length == 0)) {
+ throw new IOException("No data available in "
+ + "passed Attribute List.");
+ }
+
+ // add the Attributes
+ for (int i = 0; i < list.length; i++) {
+ attrList.addElement(list[i]);
+ }
+ }
+
+ /**
+ * Return user readable form of extension.
+ */
+ public String toString() {
+ String s = super.toString() + "SubjectDirectoryAttributes:[\n";
+
+ Enumeration<Attribute> attrs = attrList.elements();
+ while (attrs.hasMoreElements()) {
+ Attribute attr = attrs.nextElement();
+ s += attr.toString();
+ }
+
+ return (s + "]\n");
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+ decodeThis(val);
+ }
+
+ /**
+ * Encode this extension value to the output stream.
+ *
+ * @param out the DerOutputStream to encode the extension to.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id;
+ this.critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectDirectoryAttributes.");
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectDirectoryAttributes.");
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectDirectoryAttributes.");
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Returns an enumeration of attributes in the extension.
+ */
+ public Enumeration<Attribute> getAttributesList() {
+ if (attrList == null)
+ return null;
+ return attrList.elements();
+ }
+}
diff --git a/base/util/src/netscape/security/x509/SubjectKeyIdentifierExtension.java b/base/util/src/netscape/security/x509/SubjectKeyIdentifierExtension.java
new file mode 100644
index 000000000..ea0ebae82
--- /dev/null
+++ b/base/util/src/netscape/security/x509/SubjectKeyIdentifierExtension.java
@@ -0,0 +1,222 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the Subject Key Identifier Extension.
+ *
+ * This extension, if present, provides a means of identifying the particular
+ * public key used in an application. This extension by default is marked
+ * non-critical.
+ *
+ * <p>
+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a
+ * "Driving License Certificate" could have the driving license number as a extension.
+ *
+ * <p>
+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating
+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding
+ * of the extension value).
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.7
+ * @see Extension
+ * @see CertAttrSet
+ */
+public class SubjectKeyIdentifierExtension extends Extension
+ implements CertAttrSet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2457721262590880939L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT =
+ "x509.info.extensions.SubjectKeyIdentifier";
+ /**
+ * Attribute names.
+ */
+ public static final String NAME = "SubjectKeyIdentifier";
+ public static final String KEY_ID = "key_id";
+
+ // Private data member
+ private KeyIdentifier id;
+
+ // Encode this extension value
+ private void encodeThis() throws IOException {
+ DerOutputStream os = new DerOutputStream();
+ id.encode(os);
+ extensionValue = os.toByteArray();
+ }
+
+ /**
+ * Create a SubjectKeyIdentifierExtension with the passed octet string.
+ * The criticality is set to False.
+ *
+ * @param octetString the octet string identifying the key identifier.
+ */
+ public SubjectKeyIdentifierExtension(boolean critical, byte[] octetString)
+ throws IOException {
+ id = new KeyIdentifier(octetString);
+
+ this.extensionId = PKIXExtensions.SubjectKey_Id;
+ this.critical = critical;
+ encodeThis();
+ }
+
+ public SubjectKeyIdentifierExtension(byte[] octetString)
+ throws IOException {
+ id = new KeyIdentifier(octetString);
+
+ this.extensionId = PKIXExtensions.SubjectKey_Id;
+ this.critical = false;
+ encodeThis();
+ }
+
+ /**
+ * Create the extension from the passed DER encoded value.
+ *
+ * @param critical true if the extension is to be treated as critical.
+ * @param value Array of DER encoded bytes of the actual value.
+ * @exception IOException on error.
+ */
+ public SubjectKeyIdentifierExtension(Boolean critical, Object value)
+ throws IOException {
+ this.extensionId = PKIXExtensions.SubjectKey_Id;
+ this.critical = critical.booleanValue();
+
+ int len = Array.getLength(value);
+ byte[] extValue = new byte[len];
+ for (int i = 0; i < len; i++) {
+ extValue[i] = Array.getByte(value, i);
+ }
+ this.extensionValue = extValue;
+ DerValue val = new DerValue(extValue);
+ this.id = new KeyIdentifier(val);
+ }
+
+ /**
+ * Returns a printable representation.
+ */
+ public String toString() {
+ if (id == null)
+ return "";
+ String s = super.toString() + "SubjectKeyIdentifier [\n"
+ + id.toString() + "]\n";
+ return (s);
+ }
+
+ /**
+ * Write the extension to the OutputStream.
+ *
+ * @param out the OutputStream to write the extension to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(OutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ if (extensionValue == null) {
+ extensionId = PKIXExtensions.SubjectKey_Id;
+ critical = false;
+ encodeThis();
+ }
+ super.encode(tmp);
+ out.write(tmp.toByteArray());
+ }
+
+ /**
+ * Decode the extension from the InputStream.
+ *
+ * @param in the InputStream to unmarshal the contents from.
+ * @exception IOException on decoding or validity errors.
+ */
+ public void decode(InputStream in) throws IOException {
+ throw new IOException("Method not to be called directly.");
+ }
+
+ /**
+ * Set the attribute value.
+ */
+ public void set(String name, Object obj) throws IOException {
+ clearValue();
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ if (!(obj instanceof KeyIdentifier)) {
+ throw new IOException("Attribute value should be of" +
+ " type KeyIdentifier.");
+ }
+ id = (KeyIdentifier) obj;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectKeyIdentifierExtension.");
+ }
+ }
+
+ /**
+ * Get the attribute value.
+ */
+ public Object get(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ return (id);
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectKeyIdentifierExtension.");
+ }
+ }
+
+ /**
+ * Delete the attribute value.
+ */
+ public void delete(String name) throws IOException {
+ if (name.equalsIgnoreCase(KEY_ID)) {
+ id = null;
+ } else {
+ throw new IOException("Attribute name not recognized by " +
+ "CertAttrSet:SubjectKeyIdentifierExtension.");
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(KEY_ID);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/URIName.java b/base/util/src/netscape/security/x509/URIName.java
new file mode 100644
index 000000000..cc321a3b3
--- /dev/null
+++ b/base/util/src/netscape/security/x509/URIName.java
@@ -0,0 +1,85 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class implements the URIName as required by the GeneralNames
+ * ASN.1 object.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.3
+ * @see GeneralName
+ * @see GeneralNames
+ * @see GeneralNameInterface
+ */
+public class URIName implements GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8340049830612859508L;
+ private String name;
+
+ /**
+ * Create the URIName object from the passed encoded Der value.
+ *
+ * @param derValue the encoded DER URIName.
+ * @exception IOException on error.
+ */
+ public URIName(DerValue derValue) throws IOException {
+ name = derValue.getIA5String();
+ }
+
+ /**
+ * Create the URIName object with the specified name.
+ *
+ * @param name the URIName.
+ */
+ public URIName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the type of the GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_URI);
+ }
+
+ /**
+ * Encode the URI name into the DerOutputStream.
+ *
+ * @param out the DER stream to encode the URIName to.
+ * @exception IOException on encoding errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ out.putIA5String(name);
+ }
+
+ /**
+ * Convert the name into user readable string.
+ */
+ public String toString() {
+ return ("URIName: " + name);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/UniqueIdentity.java b/base/util/src/netscape/security/x509/UniqueIdentity.java
new file mode 100644
index 000000000..5113efeaf
--- /dev/null
+++ b/base/util/src/netscape/security/x509/UniqueIdentity.java
@@ -0,0 +1,112 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.BitArray;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This class defines the UniqueIdentity class used by certificates.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.6
+ */
+public class UniqueIdentity {
+ // Private data members
+ private BitArray id;
+
+ /**
+ * The default constructor for this class.
+ *
+ * @param id the byte array containing the unique identifier.
+ */
+ public UniqueIdentity(BitArray id) {
+ this.id = id;
+ }
+
+ /**
+ * The default constructor for this class.
+ *
+ * @param id the byte array containing the unique identifier.
+ */
+ public UniqueIdentity(byte[] id) {
+ this.id = new BitArray(id.length * 8, id);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param in the DerInputStream to read the UniqueIdentity from.
+ * @exception IOException on decoding errors.
+ */
+ public UniqueIdentity(DerInputStream in) throws IOException {
+ DerValue derVal = in.getDerValue();
+ id = derVal.getUnalignedBitString(true);
+ }
+
+ /**
+ * Create the object, decoding the values from the passed DER stream.
+ *
+ * @param derVal the DerValue decoded from the stream.
+ * @param tag the tag the value is encoded under.
+ * @exception IOException on decoding errors.
+ */
+ public UniqueIdentity(DerValue derVal) throws IOException {
+ id = derVal.getUnalignedBitString(true);
+ }
+
+ /**
+ * Return the UniqueIdentity as a printable string.
+ */
+ public String toString() {
+ return ("UniqueIdentity:" + id.toString() + "\n");
+ }
+
+ /**
+ * Encode the UniqueIdentity in DER form to the stream.
+ *
+ * @param out the DerOutputStream to marshal the contents to.
+ * @param tag enocode it under the following tag.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out, byte tag) throws IOException {
+ byte[] bytes = id.toByteArray();
+ int excessBits = bytes.length * 8 - id.length();
+
+ out.write(tag);
+ out.putLength(bytes.length + 1);
+
+ out.write(excessBits);
+ out.write(bytes);
+ }
+
+ /**
+ * Return the unique id.
+ */
+ public boolean[] getId() {
+ if (id == null)
+ return null;
+
+ return id.toBooleanArray();
+ }
+}
diff --git a/base/util/src/netscape/security/x509/UserNotice.java b/base/util/src/netscape/security/x509/UserNotice.java
new file mode 100644
index 000000000..dc2e1d535
--- /dev/null
+++ b/base/util/src/netscape/security/x509/UserNotice.java
@@ -0,0 +1,96 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Represent the UserNotice Qualifier.
+ *
+ * UserNotice ::= SEQUENCE {
+ * noticeRef NoticeReference OPTIONAL,
+ * explicitText DisplayText OPTIONAL
+ * }
+ *
+ * @author Thomas Kwan
+ */
+public class UserNotice extends Qualifier {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5770869942793748051L;
+ private NoticeReference mNoticeReference = null;
+ private DisplayText mDisplayText = null;
+
+ public UserNotice(NoticeReference ref, DisplayText text) {
+ mNoticeReference = ref;
+ mDisplayText = text;
+ }
+
+ public UserNotice(DerValue val) throws IOException {
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid encoding for UserNotice");
+ }
+ // case 0: no element
+ if (val.data.available() == 0)
+ return;
+ // case 1: 1 element
+ DerValue inSeq = val.data.getDerValue();
+ if (inSeq.tag == DerValue.tag_Sequence) {
+ mNoticeReference = new NoticeReference(inSeq);
+ } else {
+ mDisplayText = new DisplayText(inSeq);
+ }
+ if (val.data.available() == 0)
+ return;
+ // case 2: 2 elements
+ mDisplayText = new DisplayText(val.data.getDerValue());
+ }
+
+ public NoticeReference getNoticeReference() {
+ return mNoticeReference;
+ }
+
+ public DisplayText getDisplayText() {
+ return mDisplayText;
+ }
+
+ /**
+ * Write the UserNotice to the DerOutputStream.
+ *
+ * @param out the DerOutputStream to write the object to.
+ * @exception IOException on errors.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ // OPTIONAL
+ if (mNoticeReference != null) {
+ mNoticeReference.encode(tmp);
+ }
+ // OPTIONAL
+ if (mDisplayText != null) {
+ mDisplayText.encode(tmp);
+ }
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X500Name.java b/base/util/src/netscape/security/x509/X500Name.java
new file mode 100644
index 000000000..d44003baa
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X500Name.java
@@ -0,0 +1,699 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * X.500 names are used to identify entities, such as those which are
+ * identified by X.509 certificates. They are world-wide, hierarchical,
+ * and descriptive. Entities can be identified by attributes, and in
+ * some systems can be searched for according to those attributes.
+ *
+ * <P>
+ * <em>This class exposes only partial X.500 name functionality. Most
+ * notably, it works best if Relative Distinguished Names only have one
+ * (unique) attribute each, and if only the most common attributes need
+ * to be visible to applications. This limitation, and others, will
+ * be lifted over time.</em>
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.35
+ * @see GeneralName
+ * @see GeneralNames
+ * @see GeneralNameInterface
+ * @see RDN
+ * @see AVA
+ * @see LdapDNStrConverter
+ */
+
+public class X500Name implements Principal, GeneralNameInterface {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -730790062013191108L;
+
+ /**
+ * Constructs a name from a Ldap DN string, such
+ * as &lb;CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US&rb;. The
+ * older "/C=US/O=Sun Microsystems, Inc/OU=JavaSoft/CN=Dave" syntax
+ * is not currently supported. (The former is RFC 1779 style.)
+ *
+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779
+ */
+ public X500Name(String ldapDNString)
+ throws IOException {
+ X500Name x500name;
+
+ if (ldapDNString == null || ldapDNString.equals("")) {
+ clear();
+ return;
+ }
+ x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString);
+ names = x500name.getNames();
+ }
+
+ /**
+ * Constructs a X500Name from a Ldap DN String using the specified
+ * LdapDNStrConverter. Also use the input tags.
+ *
+ * @see LdapDNStrConverter
+ *
+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779.
+ * @param ldapDNStrConverter A LdapDNStrConverter
+ */
+ public X500Name(String ldapDNString, LdapDNStrConverter ldapDNStrConverter, byte[] tags)
+ throws IOException {
+
+ if (ldapDNString == null || ldapDNString.equals("")) {
+ clear();
+ return;
+ }
+ X500Name x500name;
+ x500name = ldapDNStrConverter.parseDN(ldapDNString, tags);
+ names = x500name.getNames();
+
+ }
+
+ public X500Name(String ldapDNString, byte[] tags)
+ throws IOException {
+ if (ldapDNString == null || ldapDNString.equals("")) {
+ clear();
+ return;
+ }
+ X500Name x500name;
+ x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString, tags);
+ names = x500name.getNames();
+ }
+
+ /**
+ * Constructs a X500Name from a Ldap DN String using the specified
+ * LdapDNStrConverter.
+ *
+ * @see LdapDNStrConverter
+ *
+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779.
+ * @param ldapDNStrConverter A LdapDNStrConverter
+ */
+ public X500Name(String ldapDNString,
+ LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ if (ldapDNString == null || ldapDNString.equals("")) {
+ clear();
+ return;
+ }
+ X500Name x500name;
+ x500name = ldapDNStrConverter.parseDN(ldapDNString);
+ names = x500name.getNames();
+ }
+
+ /**
+ * Constructs a X500Name from fields common in enterprise application
+ * environments.
+ *
+ * @param commonName common name of a person, e.g. "Vivette Davis"
+ * @param organizationUnit small organization name, e.g. "Purchasing"
+ * @param organizationName large organization name, e.g. "Onizuka, Inc."
+ * @param country two letter country code, e.g. "CH"
+ */
+ public X500Name(
+ String commonName,
+ String organizationUnit,
+ String organizationName,
+ String country) throws IOException {
+ DirStrConverter dirStrConverter = new DirStrConverter();
+ PrintableConverter printableConverter = new PrintableConverter();
+ AVA[] assertion = new AVA[1]; // array is cloned in constructors.
+ int i = 4;
+
+ names = new RDN[i];
+ /*
+ * NOTE: it's only on output that little-endian
+ * ordering is used.
+ */
+ assertion[0] = new AVA(commonName_oid,
+ dirStrConverter.getValue(commonName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(orgUnitName_oid,
+ dirStrConverter.getValue(organizationUnit));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(orgName_oid,
+ dirStrConverter.getValue(organizationName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(countryName_oid,
+ printableConverter.getValue(country));
+ names[--i] = new RDN(assertion);
+ }
+
+ /**
+ * Constructs a X500Name from fields common in Internet application
+ * environments.
+ *
+ * @param commonName common name of a person, e.g. "Vivette Davis"
+ * @param organizationUnit small organization name, e.g. "Purchasing"
+ * @param organizationName large organization name, e.g. "Onizuka, Inc."
+ * @param localityName locality (city) name, e.g. "Palo Alto"
+ * @param stateName state name, e.g. "California"
+ * @param country two letter country code, e.g. "CH"
+ */
+ public X500Name(
+ String commonName,
+ String organizationUnit,
+ String organizationName,
+ String localityName,
+ String stateName,
+ String country) throws IOException {
+ DirStrConverter dirStrConverter = new DirStrConverter();
+ PrintableConverter printableConverter = new PrintableConverter();
+ AVA[] assertion = new AVA[1]; // array is cloned in constructors.
+ int i = 6;
+
+ names = new RDN[i];
+ /*
+ * NOTE: it's only on output that little-endian
+ * ordering is used.
+ */
+ assertion[0] = new AVA(commonName_oid,
+ dirStrConverter.getValue(commonName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(orgUnitName_oid,
+ dirStrConverter.getValue(organizationUnit));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(orgName_oid,
+ dirStrConverter.getValue(organizationName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(localityName_oid,
+ dirStrConverter.getValue(localityName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(stateName_oid,
+ dirStrConverter.getValue(stateName));
+ names[--i] = new RDN(assertion);
+
+ assertion[0] = new AVA(countryName_oid,
+ printableConverter.getValue(country));
+ names[--i] = new RDN(assertion);
+ }
+
+ /**
+ * Constructs a name from an ASN.1 encoded value. The encoding
+ * of the name in the stream uses DER (a BER/1 subset).
+ *
+ * @param value a DER-encoded value holding an X.500 name.
+ */
+ public X500Name(DerValue value) throws IOException {
+
+ this(value.toDerInputStream());
+ }
+
+ /**
+ * Constructs a name from an ASN.1 encoded input stream. The encoding
+ * of the name in the stream uses DER (a BER/1 subset).
+ *
+ * @param in DER-encoded data holding an X.500 name.
+ */
+ public X500Name(DerInputStream in)
+ throws IOException {
+ parseDER(in);
+ }
+
+ /**
+ * Constructs a name from an ASN.1 encoded byte array.
+ *
+ * @param name DER-encoded byte array holding an X.500 name.
+ */
+ public X500Name(byte[] name)
+ throws IOException {
+ DerInputStream in = new DerInputStream(name);
+ parseDER(in);
+
+ }
+
+ /**
+ * Constructs a X500Name from array of RDN. The RDNs are expected to
+ * be in big endian order i.e. most significant first.
+ *
+ * @param rdns an array of RDN.
+ */
+ public X500Name(RDN[] rdns)
+ throws IOException {
+ names = (RDN[]) rdns.clone();
+ }
+
+ /**
+ * convenience method.
+ *
+ * @param rdns a vector of rdns.
+ */
+ public X500Name(Vector<RDN> rdnVector)
+ throws IOException {
+ int size = rdnVector.size();
+ names = new RDN[size];
+ for (int i = 0; i < size; i++) {
+ names[i] = (RDN) rdnVector.elementAt(i);
+ }
+ }
+
+ /**
+ * Compares this name with another, for equality.
+ *
+ * @return true iff the names are identical.
+ */
+ synchronized public boolean equals(X500Name other) {
+ int i;
+
+ if (this == other)
+ return true;
+
+ if (names.length != other.names.length)
+ return false;
+ for (i = 0; i < names.length; i++) {
+ if (!names[i].equals(other.names[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sets private data to a null state
+ */
+
+ private void clear() {
+ dn = "";
+ names = null;
+
+ }
+
+ /**
+ * Returns the name component as a Java string, regardless of its
+ * encoding restrictions.
+ */
+ private String getString(DerValue attribute) throws IOException {
+ String value = attribute.getAsString();
+
+ if (value == null)
+ throw new IOException("not a DER string encoding, "
+ + attribute.tag);
+ else
+ return value;
+ }
+
+ /**
+ * Return type of GeneralName.
+ */
+ public int getType() {
+ return (GeneralNameInterface.NAME_DIRECTORY);
+ }
+
+ /**
+ * Returns a "Country" name component. If more than one
+ * such attribute exists, the topmost one is returned.
+ *
+ * @return "C=" component of the name, if any.
+ */
+ public String getCountry() throws IOException {
+ DerValue attr = findAttribute(countryName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns an "Organization" name component. If more than
+ * one such attribute exists, the topmost one is returned.
+ *
+ * @return "O=" component of the name, if any.
+ */
+ public String getOrganization() throws IOException {
+ DerValue attr = findAttribute(orgName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns an "Organizational Unit" name component. If more
+ * than one such attribute exists, the topmost one is returned.
+ *
+ * @return "OU=" component of the name, if any.
+ */
+ public String getOrganizationalUnit() throws IOException {
+ DerValue attr = findAttribute(orgUnitName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns a "Common Name" component. If more than one such
+ * attribute exists, the topmost one is returned.
+ *
+ * @return "CN=" component of the name, if any.
+ */
+ public String getCommonName() throws IOException {
+ DerValue attr = findAttribute(commonName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns a "UID" component. If more than one such
+ * attribute exists, the topmost one is returned.
+ *
+ * @return "UID=" component of the name, if any.
+ */
+ public String getUserID() throws IOException {
+ DerValue attr = findAttribute(uidName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns a "Locality" name component. If more than one
+ * such component exists, the topmost one is returned.
+ *
+ * @return "L=" component of the name, if any.
+ */
+ public String getLocality() throws IOException {
+ DerValue attr = findAttribute(localityName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns a "State" name component. If more than one
+ * such component exists, the topmost one is returned.
+ *
+ * @return "S=" component of the name, if any.
+ */
+ public String getState() throws IOException {
+ DerValue attr = findAttribute(stateName_oid);
+
+ return getString(attr);
+ }
+
+ /**
+ * Returns a "Email" name component. If more than one
+ * such component exists, the topmost one is returned.
+ *
+ * @return "E=" component of the name, if any.
+ */
+ public String getEmail() throws IOException {
+ DerValue attr = findAttribute(email_oid);
+ if (attr == null)
+ return null;
+ return getString(attr);
+ }
+
+ /**
+ * Returns a Ldap DN String from the X500Name using the global default
+ * LdapDNStrConverter
+ *
+ * @see LdapDNStrConverter
+ * @return Ldap DN string of this X500Name using the default converter.
+ */
+ public String toLdapDNString()
+ throws IOException {
+ if (dn == null)
+ generateDN(LdapDNStrConverter.getDefault());
+ return dn;
+ }
+
+ /**
+ * Returns a Ldap DN String from the X500Name
+ * using the specified LdapDNStrconverter.
+ * For example, RFC1779String converter can be passed to convert the
+ * DN to RFC1779 string syntax.
+ *
+ * @see LdapDNStrConverter
+ * @param ldapDNStrConverter a LdapDNStrConverter
+ * @return Ldap DN string of the X500Name
+ */
+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+
+ if (dn == null)
+ generateDN(ldapDNStrConverter);
+ return dn;
+ }
+
+ /**
+ * Returns a Ldap DN string, using the global default LdapDNStrConverter
+ * or null if an error occurs in the conversion.
+ */
+ public String toString() {
+ String s;
+ if (names == null) {
+ s = "";
+ return s;
+ }
+ try {
+ s = toLdapDNString();
+ } catch (IOException e) {
+ return null;
+ }
+ return s;
+ }
+
+ /**
+ * Returns the value of toString(). This call is needed to
+ * implement the java.security.Principal interface.
+ */
+ public String getName() {
+ return toString();
+ }
+
+ private String dn; // RFC 1779 style DN, or null
+ private RDN names[]; // RDNs
+
+ /**
+ * Find the first instance of this attribute in a "top down"
+ * search of all the attributes in the name.
+ */
+ private DerValue findAttribute(ObjectIdentifier attribute) {
+ int i;
+ DerValue retval = null;
+
+ for (i = 0; i < names.length; i++) {
+ retval = names[i].findAttribute(attribute);
+ if (retval != null)
+ break;
+ }
+ return retval;
+ }
+
+ /**
+ * Returns an enumerator of RDNs in the X500Name.
+ *
+ * @return enumeration of rdns in this X500Name.
+ */
+ public Enumeration<RDN> getRDNs() {
+ return new RDNEnumerator();
+ }
+
+ /**
+ * Returns an array of RDN in the X500Name.
+ *
+ * @return array of RDN in this X500name.
+ */
+ public RDN[] getNames() {
+ return (RDN[]) names.clone();
+ }
+
+ /**
+ * Returns the number of RDNs in the X500Name.
+ *
+ * @return number of RDNs in this X500Name.
+ */
+ public int getNamesLength() {
+ return names.length;
+ }
+
+ /****************************************************************/
+
+ private void parseDER(DerInputStream in) throws IOException {
+ //
+ // X.500 names are a "SEQUENCE OF" RDNs, which means one or
+ // more and order matters. We scan them in order, which
+ // conventionally is big-endian.
+ //
+ DerValue nameseq[] = in.getSequence(5);
+ int i;
+
+ if (nameseq.length != 0) {
+ names = new RDN[nameseq.length];
+ } else {
+ clear();
+ }
+
+ for (i = 0; i < nameseq.length; i++)
+ names[i] = new RDN(nameseq[i]);
+ }
+
+ /**
+ * Encodes the name in DER-encoded form.
+ *
+ * @param out where to put the DER-encoded X.500 name
+ */
+ public void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ int i;
+
+ int len = 0;
+ if (names == null) {
+ len = 0;
+ } else {
+ len = names.length;
+
+ }
+
+ for (i = 0; i < len; i++)
+ names[i].encode(tmp);
+
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /**
+ * Gets the name in DER-encoded form.
+ *
+ * @return the DER encoded byte array of this name,
+ * null if no names are present.
+ */
+ public byte[] getEncoded() throws IOException {
+
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ int len = 0;
+
+ if (names == null) {
+ len = 0;
+ } else {
+ len = names.length;
+ }
+
+ for (int i = 0; i < len; i++)
+ names[i].encode(tmp);
+
+ out.write(DerValue.tag_Sequence, tmp);
+ return out.toByteArray();
+ }
+
+ /*
+ * Dump the printable form of a distinguished name. Each relative
+ * name is separated from the next by a ",", and assertions in the
+ * relative names have "label=value" syntax.
+ *
+ * Uses RFC 1779 syntax (i.e. little-endian, comma separators)
+ *
+ */
+ private void generateDN(LdapDNStrConverter ldapDNStrConverter)
+ throws IOException {
+ if (names == null)
+ return;
+
+ dn = ldapDNStrConverter.encodeDN(this);
+ }
+
+ private class RDNEnumerator implements Enumeration<RDN> {
+ private int index;
+
+ public RDNEnumerator() {
+ index = 0;
+ }
+
+ public boolean hasMoreElements() {
+ return (index < names.length);
+ }
+
+ public RDN nextElement() {
+ if (index >= names.length)
+ return null;
+ return names[index++];
+ }
+ }
+
+ /****************************************************************/
+
+ /*
+ * Maybe return a preallocated OID, to reduce storage costs
+ * and speed recognition of common X.500 attributes.
+ */
+ static ObjectIdentifier intern(ObjectIdentifier oid)
+ throws IOException {
+ return X500NameAttrMap.getDefault().getOid(oid);
+ }
+
+ /*
+ * Selected OIDs from X.520
+ */
+
+ /** OID for the "CN=" attribute, denoting a person's common name. */
+ public static final ObjectIdentifier commonName_oid = X500NameAttrMap.getDefault().getOid("CN");
+
+ /** OID for the "UID=" attribute, denoting a person's ID. */
+ public static final ObjectIdentifier uidName_oid = X500NameAttrMap.getDefault().getOid("UID");
+
+ /** OID for the "C=" attribute, denoting a country. */
+ public static final ObjectIdentifier countryName_oid = X500NameAttrMap.getDefault().getOid("C");
+
+ /** OID for the "L=" attribute, denoting a locality (such as a city) */
+ public static final ObjectIdentifier localityName_oid = X500NameAttrMap.getDefault().getOid("L");
+
+ /** OID for the "O=" attribute, denoting an organization name */
+ public static final ObjectIdentifier orgName_oid = X500NameAttrMap.getDefault().getOid("O");
+
+ /** OID for the "OU=" attribute, denoting an organizational unit name */
+ public static final ObjectIdentifier orgUnitName_oid = X500NameAttrMap.getDefault().getOid("OU");
+
+ /** OID for the "S=" attribute, denoting a state (such as Delaware) */
+ public static final ObjectIdentifier stateName_oid = X500NameAttrMap.getDefault().getOid("ST");
+
+ /** OID for the "STREET=" attribute, denoting a street address. */
+ public static final ObjectIdentifier streetAddress_oid = X500NameAttrMap.getDefault().getOid("STREET");
+
+ /** OID for the "T=" attribute, denoting a person's title. */
+ public static final ObjectIdentifier title_oid = X500NameAttrMap.getDefault().getOid("TITLE");
+
+ /** OID for the "E=" attribute, denoting a person's email address. */
+ public static final ObjectIdentifier email_oid = X500NameAttrMap.getDefault().getOid("E");
+
+ /*
+ * OIDs from other sources which show up in X.500 names we
+ * expect to deal with often
+ */
+
+ private static final int ipAddress_data[] = // SKIP
+ { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 };
+
+ /** OID for "IP=" IP address attributes, used with SKIP. */
+ public static final ObjectIdentifier ipAddress_oid = new ObjectIdentifier(ipAddress_data);
+}
diff --git a/base/util/src/netscape/security/x509/X500NameAttrMap.java b/base/util/src/netscape/security/x509/X500NameAttrMap.java
new file mode 100644
index 000000000..1c87c79b8
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X500NameAttrMap.java
@@ -0,0 +1,376 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * Maps an attribute name in an X500 AVA to its OID and a
+ * converter for the attribute type. The converter converts from a string to
+ * its DER encoded attribute value. * For example, "CN" maps to its OID of
+ * 2.5.4.3 and the Directory String Converter. The Directory String
+ * Converter converts from a string to a DerValue with tag Printable, T.61 or
+ * UniversalString.
+ *
+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc.
+ *
+ */
+
+public class X500NameAttrMap {
+ //
+ // public constructors.
+ //
+
+ /**
+ * Construct a X500NameAttrMap.
+ */
+ public X500NameAttrMap() {
+ }
+
+ //
+ // public get methods.
+ //
+
+ /**
+ * Get the attribute name (keyword) of the specified OID.
+ *
+ * @param oid An ObjectIdentifier
+ *
+ * @return An attribute name (keyword string) for the OID.
+ */
+ public String getName(ObjectIdentifier oid) {
+ // XXX assert oid != null
+ return oid2Name.get(oid);
+ }
+
+ /**
+ * Get the ObjectIdentifier of the attribute name.
+ *
+ * @param name An attribute name (string of ascii characters)
+ *
+ * @return An ObjectIdentifier for the attribute.
+ */
+ public ObjectIdentifier getOid(String name) {
+ // XXX assert name != null
+ return name2OID.get(name.toUpperCase());
+ }
+
+ /**
+ * Get the Attribute Value Converter for the specified attribute name.
+ *
+ * @param name An attribute name
+ *
+ * @return An attribute value converter for the attribute name
+ */
+ public AVAValueConverter getValueConverter(String name) {
+ ObjectIdentifier oid =
+ name2OID.get(name.toUpperCase());
+ if (oid == null)
+ return null;
+ return (AVAValueConverter) oid2ValueConverter.get(oid);
+ }
+
+ /**
+ * Get the Attribute Value Converter for the specified ObjectIdentifier.
+ *
+ * @param oid An ObjectIdentifier
+ *
+ * @return An AVAValueConverter for the OID.
+ */
+ public AVAValueConverter getValueConverter(ObjectIdentifier oid) {
+ return (AVAValueConverter) oid2ValueConverter.get(oid);
+ }
+
+ /**
+ * Get an Enumeration of all attribute names in this map.
+ *
+ * @return An Enumeration of all attribute names.
+ */
+ public Enumeration<String> getAllNames() {
+ return name2OID.keys();
+ }
+
+ /**
+ * Get an Enumeration of all ObjectIdentifiers in this map.
+ *
+ * @return An Enumeration of all OIDs in this map.
+ */
+ public Enumeration<ObjectIdentifier> getAllOIDs() {
+ return oid2Name.keys();
+ }
+
+ /**
+ * Get the ObjectIdentifier object in the map for the specified OID.
+ *
+ * @param oid An ObjectIdentifier.
+ * @return The ObjectIdentifier object in this map for the OID.
+ */
+ public ObjectIdentifier getOid(ObjectIdentifier oid) {
+ String name = oid2Name.get(oid);
+ if (name == null)
+ return null;
+ return name2OID.get(name);
+ }
+
+ //
+ // public add methods.
+ //
+
+ /**
+ * Adds a attribute name, ObjectIdentifier, AVAValueConverter entry
+ * to the map.
+ *
+ * @param name An attribute name (string of ascii chars)
+ * @param oid The ObjectIdentifier for the attribute.
+ * @param valueConverter An AVAValueConverter object for converting
+ * an value for this attribute from a string to
+ * a DerValue and vice versa.
+ */
+ public void addNameOID(String name, ObjectIdentifier oid,
+ AVAValueConverter valueConverter) {
+ // normalize name for case insensitive compare.
+ ObjectIdentifier theOid;
+ Class<? extends AVAValueConverter> expValueConverter;
+
+ theOid = name2OID.get(name);
+ if (theOid != null) {
+ expValueConverter = oid2ValueConverter.get(theOid).getClass();
+ if (!theOid.equals(oid) ||
+ expValueConverter != valueConverter.getClass()) {
+ throw new IllegalArgumentException(
+ "Another keyword-oid-valueConverter triple already " +
+ "exists in the X500NameAttrMap ");
+ }
+ return;
+ }
+ name2OID.put(name.toUpperCase(), oid);
+ oid2Name.put(oid, name.toUpperCase());
+ oid2ValueConverter.put(oid, valueConverter);
+ }
+
+ //
+ // public static methods.
+ //
+
+ /**
+ * Get the global default X500NameAttrMap.
+ *
+ * @return The global default X500NameAttrMap.
+ */
+ public static X500NameAttrMap getDefault() {
+ return defMap;
+ }
+
+ /**
+ * Get the global default X500NamAttrMap using the DirStrConverter.
+ *
+ * @return The global default X500NameAttrMap using the DirStrConverter.
+ */
+
+ public static X500NameAttrMap getDirDefault() {
+ return defDirMap;
+
+ }
+
+ /**
+ * Set the global default X500NameAttrMap.
+ *
+ * @param newDefault The new default X500NameAttrMap.
+ */
+ public static void setDefault(X500NameAttrMap newDefault) {
+ // XXX assert newDef != null
+ defMap = newDefault;
+ }
+
+ //
+ // private variables
+ //
+
+ Hashtable<String, ObjectIdentifier> name2OID = new Hashtable<String, ObjectIdentifier>();
+ Hashtable<ObjectIdentifier, String> oid2Name = new Hashtable<ObjectIdentifier, String>();
+ Hashtable<ObjectIdentifier, AVAValueConverter> oid2ValueConverter =
+ new Hashtable<ObjectIdentifier, AVAValueConverter>();
+
+ //
+ // global defaults.
+ //
+
+ private static X500NameAttrMap defMap;
+
+ private static X500NameAttrMap defDirMap;
+
+ /*
+ * Create the default maps on initialization.
+ */
+ static {
+ defMap = new X500NameAttrMap();
+ AVAValueConverter directoryStr = new DirStrConverter(), ia5Str = new IA5StringConverter();
+ defMap.addNameOID("CN",
+ new ObjectIdentifier("2.5.4.3"),
+ directoryStr);
+ defMap.addNameOID("OU",
+ new ObjectIdentifier("2.5.4.11"),
+ directoryStr);
+ defMap.addNameOID("O",
+ new ObjectIdentifier("2.5.4.10"),
+ directoryStr);
+ // serialNumber added for CEP support
+ defMap.addNameOID("SERIALNUMBER",
+ new ObjectIdentifier("2.5.4.5"),
+ new PrintableConverter());
+ defMap.addNameOID("C",
+ new ObjectIdentifier("2.5.4.6"),
+ new PrintableConverter());
+ defMap.addNameOID("L",
+ new ObjectIdentifier("2.5.4.7"),
+ directoryStr);
+ defMap.addNameOID("ST",
+ new ObjectIdentifier("2.5.4.8"),
+ directoryStr);
+ defMap.addNameOID("STREET",
+ new ObjectIdentifier("2.5.4.9"),
+ directoryStr);
+ defMap.addNameOID("TITLE",
+ new ObjectIdentifier("2.5.4.12"),
+ directoryStr);
+ // RFC 1274 UserId, rfc822MailBox
+ defMap.addNameOID("UID",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.1"),
+ directoryStr);
+ defMap.addNameOID("MAIL",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.3"),
+ ia5Str);
+ // PKCS9 e-mail address
+ defMap.addNameOID("E",
+ new ObjectIdentifier("1.2.840.113549.1.9.1"),
+ ia5Str);
+
+ // DC definition from draft-ietf-asid-ldap-domains-02.txt
+ defMap.addNameOID("DC",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.25"),
+ ia5Str);
+
+ // more defined in RFC2459 used in Subject Directory Attr extension
+ defMap.addNameOID("SN", // surname
+ new ObjectIdentifier("2.5.4.4"),
+ directoryStr);
+ defMap.addNameOID("GIVENNAME",
+ new ObjectIdentifier("2.5.4.42"),
+ directoryStr);
+ defMap.addNameOID("INITIALS",
+ new ObjectIdentifier("2.5.4.43"),
+ directoryStr);
+ defMap.addNameOID("GENERATIONQUALIFIER",
+ new ObjectIdentifier("2.5.4.44"),
+ directoryStr);
+ defMap.addNameOID("DNQUALIFIER",
+ new ObjectIdentifier("2.5.4.46"),
+ directoryStr);
+
+ // these two added mainly for CEP support
+ // PKCS9 unstructured name
+ defMap.addNameOID("UNSTRUCTUREDNAME",
+ new ObjectIdentifier("1.2.840.113549.1.9.2"),
+ ia5Str);
+ // PKCS9 unstructured address
+ defMap.addNameOID("UNSTRUCTUREDADDRESS",
+ new ObjectIdentifier("1.2.840.113549.1.9.8"),
+ new PrintableConverter());
+ };
+
+ static {
+ defDirMap = new X500NameAttrMap();
+ AVAValueConverter directoryStr = new DirStrConverter();
+
+ defDirMap.addNameOID("CN",
+ new ObjectIdentifier("2.5.4.3"),
+ directoryStr);
+ defDirMap.addNameOID("OU",
+ new ObjectIdentifier("2.5.4.11"),
+ directoryStr);
+ defDirMap.addNameOID("O",
+ new ObjectIdentifier("2.5.4.10"),
+ directoryStr);
+ // serialNumber added for CEP support
+ defDirMap.addNameOID("SERIALNUMBER",
+ new ObjectIdentifier("2.5.4.5"),
+ directoryStr);
+ defDirMap.addNameOID("C",
+ new ObjectIdentifier("2.5.4.6"),
+ directoryStr);
+ defDirMap.addNameOID("L",
+ new ObjectIdentifier("2.5.4.7"),
+ directoryStr);
+ defDirMap.addNameOID("ST",
+ new ObjectIdentifier("2.5.4.8"),
+ directoryStr);
+ defDirMap.addNameOID("STREET",
+ new ObjectIdentifier("2.5.4.9"),
+ directoryStr);
+ defDirMap.addNameOID("TITLE",
+ new ObjectIdentifier("2.5.4.12"),
+ directoryStr);
+ // RFC 1274 UserId, rfc822MailBox
+ defDirMap.addNameOID("UID",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.1"),
+ directoryStr);
+ defDirMap.addNameOID("MAIL",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.3"),
+ directoryStr);
+ // PKCS9 e-mail address
+ defDirMap.addNameOID("E",
+ new ObjectIdentifier("1.2.840.113549.1.9.1"),
+ directoryStr);
+
+ // DC definition from draft-ietf-asid-ldap-domains-02.txt
+ defDirMap.addNameOID("DC",
+ new ObjectIdentifier("0.9.2342.19200300.100.1.25"),
+ directoryStr);
+
+ // more defined in RFC2459 used in Subject Directory Attr extension
+ defDirMap.addNameOID("SN", // surname
+ new ObjectIdentifier("2.5.4.4"),
+ directoryStr);
+ defDirMap.addNameOID("GIVENNAME",
+ new ObjectIdentifier("2.5.4.42"),
+ directoryStr);
+ defDirMap.addNameOID("INITIALS",
+ new ObjectIdentifier("2.5.4.43"),
+ directoryStr);
+ defDirMap.addNameOID("GENERATIONQUALIFIER",
+ new ObjectIdentifier("2.5.4.44"),
+ directoryStr);
+ defDirMap.addNameOID("DNQUALIFIER",
+ new ObjectIdentifier("2.5.4.46"),
+ directoryStr);
+
+ // these two added mainly for CEP support
+ // PKCS9 unstructured name
+ defDirMap.addNameOID("UNSTRUCTUREDNAME",
+ new ObjectIdentifier("1.2.840.113549.1.9.2"),
+ directoryStr);
+ // PKCS9 unstructured address
+ defDirMap.addNameOID("UNSTRUCTUREDADDRESS",
+ new ObjectIdentifier("1.2.840.113549.1.9.8"),
+ directoryStr);
+ };
+
+}
diff --git a/base/util/src/netscape/security/x509/X500Signer.java b/base/util/src/netscape/security/x509/X500Signer.java
new file mode 100644
index 000000000..0b8cf87a4
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X500Signer.java
@@ -0,0 +1,116 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.Signer;
+
+/**
+ * This class provides a binding between a Signature object and an
+ * authenticated X.500 name (from an X.509 certificate chain), which
+ * is needed in many public key signing applications.
+ *
+ * <P>
+ * The name of the signer is important, both because knowing it is the whole point of the signature, and because the
+ * associated X.509 certificate is always used to verify the signature.
+ *
+ * <P>
+ * <em>The X.509 certificate chain is temporarily not associated with
+ * the signer, but this omission will be resolved.</em>
+ *
+ * @version 1.18
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+public final class X500Signer extends Signer {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3148659822293810158L;
+
+ /**
+ * Called for each chunk of the data being signed. That
+ * is, you can present the data in many chunks, so that
+ * it doesn't need to be in a single sequential buffer.
+ *
+ * @param buf buffer holding the next chunk of the data to be signed
+ * @param offset starting point of to-be-signed data
+ * @param len how many bytes of data are to be signed
+ * @exception SignatureException on errors.
+ */
+ public void update(byte buf[], int offset, int len)
+ throws SignatureException {
+ sig.update(buf, offset, len);
+ }
+
+ /**
+ * Produces the signature for the data processed by update().
+ *
+ * @exception SignatureException on errors.
+ */
+ public byte[] sign() throws SignatureException {
+ return sig.sign();
+ }
+
+ /**
+ * Returns the algorithm used to sign.
+ */
+ public AlgorithmId getAlgorithmId() {
+ return algid;
+ }
+
+ /**
+ * Returns the name of the signing agent.
+ */
+ public X500Name getSigner() {
+ return agent;
+ }
+
+ /*
+ * Constructs a binding between a signature and an X500 name
+ * from an X.509 certificate.
+ */
+ // package private ----hmmmmm ?????
+ public X500Signer(Signature sig, X500Name agent) {
+ if (sig == null || agent == null)
+ throw new IllegalArgumentException("null parameter");
+
+ this.sig = sig;
+ this.agent = agent;
+
+ try {
+ this.algid = AlgorithmId.getAlgorithmId(sig.getAlgorithm());
+ String alg = sig.getAlgorithm();
+ if (alg.equals("DSA")) {
+ alg = "SHA1withDSA";
+ }
+ this.algid = AlgorithmId.getAlgorithmId(alg);
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("internal error! " + e.getMessage());
+ }
+ }
+
+ private Signature sig;
+ private X500Name agent; // XXX should be X509CertChain
+ private AlgorithmId algid;
+}
diff --git a/base/util/src/netscape/security/x509/X509AttributeName.java b/base/util/src/netscape/security/x509/X509AttributeName.java
new file mode 100644
index 000000000..2f6c46cb1
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509AttributeName.java
@@ -0,0 +1,64 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+/**
+ * This class is used to parse attribute names like "x509.info.extensions".
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.4
+ */
+public class X509AttributeName {
+ // Public members
+ private static final char SEPARATOR = '.';
+
+ // Private data members
+ private String prefix = null;
+ private String suffix = null;
+
+ /**
+ * Default constructor for the class. Name is of the form
+ * "x509.info.extensions".
+ *
+ * @param name the attribute name.
+ */
+ public X509AttributeName(String name) {
+ int i = name.indexOf(SEPARATOR);
+ if (i == (-1)) {
+ prefix = name;
+ } else {
+ prefix = name.substring(0, i);
+ suffix = name.substring(i + 1);
+ }
+ }
+
+ /**
+ * Return the prefix of the name.
+ */
+ public String getPrefix() {
+ return (prefix);
+ }
+
+ /**
+ * Return the suffix of the name.
+ */
+ public String getSuffix() {
+ return (suffix);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509CRLImpl.java b/base/util/src/netscape/security/x509/X509CRLImpl.java
new file mode 100755
index 000000000..8c69b6aa0
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509CRLImpl.java
@@ -0,0 +1,1071 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * <p>
+ * An implmentation for X509 CRL (Certificate Revocation List).
+ * <p>
+ * The X.509 v2 CRL format is described below in ASN.1:
+ *
+ * <pre>
+ * </pre>
+ * <p>
+ * CertificateList ::= SEQUENCE { tbsCertList TBSCertList, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING
+ * }
+ * <p>
+ * A good description and profiling is provided in the IETF PKIX WG draft, Part I: X.509 Certificate and CRL Profile,
+ * &lt;draft-ietf-pkix-ipki-part1-06.txt&gt;.
+ * <p>
+ * The ASN.1 definition of <code>tbsCertList</code> is:
+ *
+ * <pre>
+ * TBSCertList ::= SEQUENCE {
+ * version Version OPTIONAL,
+ * -- if present, must be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate ChoiceOfTime,
+ * nextUpdate ChoiceOfTime OPTIONAL,
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate ChoiceOfTime,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, must be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, must be v2
+ * }
+ * </pre>
+ *
+ * @author Hemma Prafullchandra
+ * @version 1.8
+ * @see X509CRL
+ */
+public class X509CRLImpl extends X509CRL {
+
+ // CRL data, and its envelope
+ private byte[] signedCRL = null; // DER encoded crl
+ private byte[] signature = null; // raw signature bits
+ private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL
+ private AlgorithmId sigAlgId; // sig alg in CRL
+
+ // crl information
+ private int version;
+ private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
+ private X500Name issuer;
+ private Date thisUpdate = null;
+ private Date nextUpdate = null;
+ // private static final Hashtable revokedCerts = new Hashtable();
+ private Hashtable<BigInteger, RevokedCertificate> revokedCerts = new Hashtable<BigInteger, RevokedCertificate>();
+ // private static CRLExtensions extensions = null;
+ private CRLExtensions extensions = null;
+ private boolean entriesIncluded = true;
+ private final static boolean isExplicit = true;
+
+ private boolean readOnly = false;
+
+ /**
+ * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
+ * bytes. This form of constructor is used by agents which
+ * need to examine and use CRL contents. Note that the buffer
+ * must include only one CRL, and no "garbage" may be left at
+ * the end.
+ *
+ * @param crlData the encoded bytes, with no trailing padding.
+ * @exception CRLException on parsing errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public X509CRLImpl(byte[] crlData)
+ throws CRLException, X509ExtensionException {
+ try {
+ DerValue in = new DerValue(crlData);
+
+ parse(in);
+ signedCRL = crlData;
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.getMessage());
+ }
+ }
+
+ public X509CRLImpl(byte[] crlData, boolean includeEntries)
+ throws CRLException, X509ExtensionException {
+ try {
+ entriesIncluded = includeEntries;
+ DerValue in = new DerValue(crlData);
+
+ parse(in, includeEntries);
+ signedCRL = crlData;
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Unmarshals an X.509 CRL from an input stream. Only one CRL
+ * is expected at the end of the input stream.
+ *
+ * @param inStrm an input stream holding at least one CRL
+ * @exception CRLException on parsing errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public X509CRLImpl(InputStream inStrm)
+ throws CRLException, X509ExtensionException {
+ try {
+ DerValue val = new DerValue(inStrm);
+
+ parse(val);
+ signedCRL = val.toByteArray();
+ } catch (IOException e) {
+ throw new CRLException("Parsing error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Initial CRL constructor, no revoked certs, and no extensions.
+ *
+ * @param issuer the name of the CA issuing this CRL.
+ * @param thisUpdate the Date of this issue.
+ * @param nextUpdate the Date of the next CRL.
+ */
+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
+ this.issuer = issuer;
+ this.thisUpdate = thisDate;
+ this.nextUpdate = nextDate;
+ }
+
+ /**
+ * CRL constructor, revoked certs, no extensions.
+ *
+ * @param issuer the name of the CA issuing this CRL.
+ * @param thisUpdate the Date of this issue.
+ * @param nextUpdate the Date of the next CRL.
+ * @param badCerts the array of revoked certificates.
+ *
+ * @exception CRLException on parsing/construction errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
+ RevokedCertificate[] badCerts)
+ throws CRLException, X509ExtensionException {
+ this.issuer = issuer;
+ this.thisUpdate = thisDate;
+ this.nextUpdate = nextDate;
+ if (badCerts != null) {
+ for (int i = 0; i < badCerts.length; i++)
+ this.revokedCerts.put(badCerts[i].getSerialNumber(),
+ badCerts[i]);
+ }
+ }
+
+ /**
+ * CRL constructor, revoked certs and extensions.
+ *
+ * @param issuer the name of the CA issuing this CRL.
+ * @param thisUpdate the Date of this issue.
+ * @param nextUpdate the Date of the next CRL.
+ * @param badCerts the array of revoked certificates.
+ * @param crlExts the CRL extensions.
+ *
+ * @exception CRLException on parsing/construction errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
+ RevokedCertificate[] badCerts, CRLExtensions crlExts)
+ throws CRLException, X509ExtensionException {
+ this.issuer = issuer;
+ this.thisUpdate = thisDate;
+ this.nextUpdate = nextDate;
+ if (badCerts != null) {
+ for (int i = 0; i < badCerts.length; i++) {
+ if (badCerts[i] != null) {
+ this.revokedCerts.put(badCerts[i].getSerialNumber(),
+ badCerts[i]);
+ if (badCerts[i].hasExtensions())
+ this.version = 1;
+ }
+ }
+ }
+ if (crlExts != null) {
+ this.extensions = crlExts;
+ this.version = 1;
+ }
+ }
+
+ /**
+ * CRL constructor, revoked certs and extensions.
+ * This will be used by code that constructs CRL and uses
+ * encodeInfo() in order to sign it using external means
+ * (other than sign() method)
+ *
+ * @param issuer the name of the CA issuing this CRL.
+ * @param sigAlg signing algorithm id
+ * @param thisUpdate the Date of this issue.
+ * @param nextUpdate the Date of the next CRL.
+ * @param badCerts the array of revoked certificates.
+ * @param crlExts the CRL extensions.
+ */
+ public X509CRLImpl(X500Name issuer, AlgorithmId algId, Date thisDate, Date nextDate,
+ RevokedCertificate[] badCerts, CRLExtensions crlExts)
+ throws CRLException, X509ExtensionException {
+ this(issuer, thisDate, nextDate, badCerts, crlExts);
+ infoSigAlgId = algId;
+ }
+
+ /**
+ * CRL constructor, revoked certs and extensions.
+ *
+ * @param issuer the name of the CA issuing this CRL.
+ * @param sigAlg signing algorithm id
+ * @param thisUpdate the Date of this issue.
+ * @param nextUpdate the Date of the next CRL.
+ * @param badCerts the hashtable of revoked certificates.
+ * @param crlExts the CRL extensions.
+ *
+ * @exception CRLException on parsing/construction errors.
+ * @exception X509ExtensionException on extension handling errors.
+ */
+ public X509CRLImpl(X500Name issuer, AlgorithmId algId,
+ Date thisDate, Date nextDate,
+ Hashtable<BigInteger, RevokedCertificate> badCerts, CRLExtensions crlExts)
+ throws CRLException, X509ExtensionException {
+ this.issuer = issuer;
+ this.thisUpdate = thisDate;
+ this.nextUpdate = nextDate;
+ this.revokedCerts = badCerts;
+ if (crlExts != null) {
+ this.extensions = crlExts;
+ this.version = 1;
+ }
+ infoSigAlgId = algId;
+ }
+
+ /**
+ * Returns the ASN.1 DER encoded form of this CRL.
+ *
+ * @exception CRLException if an encoding error occurs.
+ */
+ public byte[] getEncoded() throws CRLException {
+ if (signedCRL == null)
+ throw new CRLException("Null CRL to encode");
+ byte[] dup = new byte[signedCRL.length];
+ System.arraycopy(signedCRL, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ /**
+ * Returns true if signedCRL was set.
+ *
+ * @param byte array of containing signed CRL.
+ */
+ public boolean setSignedCRL(byte[] crl) {
+ boolean done = false;
+ if (tbsCertList != null && signedCRL == null) {
+ signedCRL = new byte[crl.length];
+ System.arraycopy(crl, 0, signedCRL, 0, signedCRL.length);
+ done = true;
+ }
+ return done;
+ }
+
+ public boolean hasUnsupportedCriticalExtension() {
+ // XXX NOT IMPLEMENTED
+ return true;
+ }
+
+ /**
+ * Encodes the "to-be-signed" CRL to the OutputStream.
+ *
+ * @param out the OutputStream to write to.
+ * @exception CRLException on encoding errors.
+ * @exception X509ExtensionException on extension encoding errors.
+ */
+ public void encodeInfo(OutputStream out)
+ throws CRLException, X509ExtensionException {
+ try {
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream rCerts = new DerOutputStream();
+ DerOutputStream seq = new DerOutputStream();
+
+ if (version != 0) // v2 crl encode version
+ tmp.putInteger(new BigInt(version));
+ infoSigAlgId.encode(tmp);
+ issuer.encode(tmp);
+
+ // from 2050 should encode GeneralizedTime
+ tmp.putUTCTime(thisUpdate);
+
+ if (nextUpdate != null)
+ tmp.putUTCTime(nextUpdate);
+
+ if (!revokedCerts.isEmpty()) {
+ for (Enumeration<RevokedCertificate> e = revokedCerts.elements(); e.hasMoreElements();)
+ ((RevokedCertImpl) e.nextElement()).encode(rCerts);
+ tmp.write(DerValue.tag_Sequence, rCerts);
+ }
+
+ if (extensions != null)
+ extensions.encode(tmp, isExplicit);
+
+ seq.write(DerValue.tag_Sequence, tmp);
+
+ tbsCertList = seq.toByteArray();
+ out.write(tbsCertList);
+ } catch (IOException e) {
+ throw new CRLException("Encoding error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Verifies that this CRL was signed using the
+ * private key that corresponds to the specified public key.
+ *
+ * @param key the PublicKey used to carry out the verification.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException if there's no default provider.
+ * @exception SignatureException on signature errors.
+ * @exception CRLException on encoding errors.
+ */
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException {
+ verify(key, null);
+ }
+
+ /**
+ * Verifies that this CRL was signed using the
+ * private key that corresponds to the specified public key,
+ * and that the signature verification was computed by
+ * the given provider.
+ *
+ * @param key the PublicKey used to carry out the verification.
+ * @param sigProvider the name of the signature provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException on incorrect provider.
+ * @exception SignatureException on signature errors.
+ * @exception CRLException on encoding errors.
+ */
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException {
+ if (signedCRL == null) {
+ throw new CRLException("Uninitialized CRL");
+ }
+ Signature sigVerf = null;
+
+ String sigAlg = sigAlgId.getName();
+ if (sigProvider.equals("Mozilla-JSS")) {
+ if (sigAlg.equals("MD5withRSA")) {
+ sigAlg = "MD5/RSA";
+ } else if (sigAlg.equals("MD2withRSA")) {
+ sigAlg = "MD2/RSA";
+ } else if (sigAlg.equals("SHA1withRSA")) {
+ sigAlg = "SHA1/RSA";
+ } else if (sigAlg.equals("SHA1withDSA")) {
+ sigAlg = "SHA1/DSA";
+ }
+ }
+ sigVerf = Signature.getInstance(sigAlg, sigProvider);
+ sigVerf.initVerify(key);
+
+ if (tbsCertList == null)
+ throw new CRLException("Uninitialized CRL");
+
+ sigVerf.update(tbsCertList, 0, tbsCertList.length);
+
+ if (!sigVerf.verify(signature)) {
+ throw new CRLException("Signature does not match.");
+ }
+ }
+
+ /**
+ * Encodes an X.509 CRL, and signs it using the key
+ * passed.
+ *
+ * @param key the private key used for signing.
+ * @param algorithm the name of the signature algorithm used.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException on incorrect provider.
+ * @exception SignatureException on signature errors.
+ * @exception CRLException if any mandatory data was omitted.
+ * @exception X509ExtensionException on any extension errors.
+ */
+ public void sign(PrivateKey key, String algorithm)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException, X509ExtensionException {
+ sign(key, algorithm, null);
+ }
+
+ /**
+ * Encodes an X.509 CRL, and signs it using the key
+ * passed.
+ *
+ * @param key the private key used for signing.
+ * @param algorithm the name of the signature algorithm used.
+ * @param provider the name of the provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException on incorrect provider.
+ * @exception SignatureException on signature errors.
+ * @exception CRLException if any mandatory data was omitted.
+ * @exception X509ExtensionException on any extension errors.
+ */
+ public void sign(PrivateKey key, String algorithm, String provider)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException, X509ExtensionException {
+ try {
+ if (readOnly)
+ throw new CRLException("cannot over-write existing CRL");
+ Signature sigEngine = null;
+ if (provider == null)
+ sigEngine = Signature.getInstance(algorithm);
+ else
+ sigEngine = Signature.getInstance(algorithm, provider);
+
+ sigEngine.initSign(key);
+
+ // in case the name is reset
+ sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
+ infoSigAlgId = sigAlgId;
+
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ // encode crl info
+ encodeInfo(tmp);
+
+ // encode algorithm identifier
+ sigAlgId.encode(tmp);
+
+ // Create and encode the signature itself.
+ sigEngine.update(tbsCertList, 0, tbsCertList.length);
+ signature = sigEngine.sign();
+ tmp.putBitString(signature);
+
+ // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
+ out.write(DerValue.tag_Sequence, tmp);
+ signedCRL = out.toByteArray();
+ readOnly = true;
+
+ } catch (IOException e) {
+ throw new CRLException("Error while encoding data: " +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a printable string of this CRL.
+ *
+ * @return value of this CRL in a printable form.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("X.509 CRL v" + (version + 1) + "\n");
+ sb.append("Signature Algorithm: " + sigAlgId.toString() +
+ ", OID=" + (sigAlgId.getOID()).toString() + "\n");
+ sb.append("Issuer: " + issuer.toString() + "\n");
+ sb.append("\nThis Update: " + thisUpdate.toString() + "\n");
+ if (nextUpdate != null)
+ sb.append("Next Update: " + nextUpdate.toString() + "\n");
+ if (revokedCerts.isEmpty())
+ sb.append("\nNO certificates have been revoked\n");
+ else {
+ sb.append("\nRevoked Certificates:\n");
+ for (Enumeration<RevokedCertificate> e = revokedCerts.elements(); e.hasMoreElements();)
+ sb.append(((RevokedCertificate) e.nextElement()).toString());
+ }
+ if (extensions != null) {
+ for (int i = 0; i < extensions.size(); i++) {
+ sb.append("\nCRL Extension[" + i + "]: " +
+ ((Extension) (extensions.elementAt(i))).toString());
+ }
+ }
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String signaturebits = pp.toHexString(signature);
+ sb.append("\nSignature:\n" + signaturebits);
+
+ return sb.toString();
+ }
+
+ /**
+ * Checks whether the given serial number is on this CRL.
+ *
+ * @param serialNumber the number to check for.
+ * @return true if the given serial number is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(BigInteger serialNumber) {
+ if (revokedCerts == null || revokedCerts.isEmpty())
+ return false;
+ return revokedCerts.containsKey(serialNumber);
+ }
+
+ public boolean isRevoked(Certificate cert) {
+ if (cert == null)
+ return false;
+ if (cert instanceof X509Certificate) {
+ return isRevoked(((X509Certificate) cert).getSerialNumber());
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Gets the version number from the CRL.
+ * The ASN.1 definition for this is:
+ *
+ * <pre>
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ * -- v3 does not apply to CRLs but appears for consistency
+ * -- with definition of Version for certs
+ * </pre>
+ *
+ * @return the version number.
+ */
+ public int getVersion() {
+ return version;
+ }
+
+ /**
+ * Gets the issuer distinguished name from this CRL.
+ * The issuer name identifies the entity who has signed (and
+ * issued the CRL). The issuer name field contains an
+ * X.500 distinguished name (DN).
+ * The ASN.1 definition for this is:
+ *
+ * <pre>
+ * issuer Name
+ *
+ * Name ::= CHOICE { RDNSequence }
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeValueAssertion
+ *
+ * AttributeValueAssertion ::= SEQUENCE {
+ * AttributeType,
+ * AttributeValue }
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY
+ * </pre>
+ *
+ * The Name describes a hierarchical name composed of attributes,
+ * such as country name, and corresponding values, such as US.
+ * The type of the component AttributeValue is determined by the
+ * AttributeType; in general it will be a directoryString.
+ * A directoryString is usually one of PrintableString,
+ * TeletexString or UniversalString.
+ *
+ * @return the issuer name.
+ */
+ public Principal getIssuerDN() {
+ return (Principal) issuer;
+ }
+
+ /**
+ * Gets the thisUpdate date from the CRL.
+ * The ASN.1 definition for this is:
+ *
+ * @return the thisUpdate date from the CRL.
+ */
+ public Date getThisUpdate() {
+ return (new Date(thisUpdate.getTime()));
+ }
+
+ /**
+ * Gets the nextUpdate date from the CRL.
+ *
+ * @return the nextUpdate date from the CRL, or null if
+ * not present.
+ */
+ public Date getNextUpdate() {
+ if (nextUpdate == null)
+ return null;
+ return (new Date(nextUpdate.getTime()));
+ }
+
+ /**
+ * Get the revoked certificate from the CRL by the serial
+ * number provided.
+ *
+ * @return the revoked certificate or null if there is
+ * no entry in the CRL marked with the provided serial number.
+ * @see RevokedCertificate
+ */
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
+ if (revokedCerts == null || revokedCerts.isEmpty())
+ return null;
+ RevokedCertificate badCert =
+ (RevokedCertificate) revokedCerts.get(serialNumber);
+ return badCert;
+ }
+
+ /**
+ * Gets all the revoked certificates from the CRL.
+ * A Set of RevokedCertificate.
+ *
+ * @return all the revoked certificates or null if there are
+ * none.
+ * @see RevokedCertificate
+ */
+ public Set<RevokedCertificate> getRevokedCertificates() {
+ if (revokedCerts == null || revokedCerts.isEmpty())
+ return null;
+ else {
+ Set<RevokedCertificate> certSet = new LinkedHashSet<RevokedCertificate>(revokedCerts.values());
+ return certSet;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Hashtable<BigInteger, RevokedCertificate> getListOfRevokedCertificates() {
+ if (revokedCerts == null) {
+ return null;
+ } else {
+ return (Hashtable<BigInteger, RevokedCertificate>) revokedCerts.clone();
+ }
+ }
+
+ public int getNumberOfRevokedCertificates() {
+ if (revokedCerts == null)
+ return -1;
+ else
+ return revokedCerts.size();
+ }
+
+ /**
+ * Gets the DER encoded CRL information, the <code>tbsCertList</code> from this CRL.
+ * This can be used to verify the signature independently.
+ *
+ * @return the DER encoded CRL information.
+ * @exception CRLException on parsing errors.
+ * @exception X509ExtensionException on extension parsing errors.
+ */
+ public byte[] getTBSCertList()
+ throws CRLException {
+ if (tbsCertList == null)
+ throw new CRLException("Uninitialized CRL");
+ byte[] dup = new byte[tbsCertList.length];
+ System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ /**
+ * Gets the raw Signature bits from the CRL.
+ *
+ * @return the signature.
+ */
+ public byte[] getSignature() {
+ if (signature == null)
+ return null;
+ byte[] dup = new byte[signature.length];
+ System.arraycopy(signature, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ /**
+ * Returns true if signature was set.
+ *
+ * @param byte array of containing CRL signature.
+ */
+ public boolean setSignature(byte[] crlSignature) {
+ boolean done = false;
+ if (tbsCertList != null && signature == null) {
+ signature = new byte[crlSignature.length];
+ System.arraycopy(crlSignature, 0, signature, 0, signature.length);
+ done = true;
+ }
+ return done;
+ }
+
+ /**
+ * Gets the signature algorithm name for the CRL
+ * signature algorithm. For example, the string "SHA1withDSA".
+ * The ASN.1 definition for this is:
+ *
+ * <pre>
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * -- contains a value of the type
+ * -- registered for use with the
+ * -- algorithm object identifier value
+ * </pre>
+ *
+ * @return the signature algorithm name.
+ */
+ public String getSigAlgName() {
+ if (sigAlgId == null)
+ return null;
+ return sigAlgId.getName();
+ }
+
+ /**
+ * Gets the signature algorithm OID string from the CRL.
+ * An OID is represented by a set of positive whole number separated
+ * by ".", that means,<br>
+ * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
+ * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
+ * with DSA signature algorithm, as per the PKIX part I.
+ *
+ * @return the signature algorithm oid string.
+ */
+ public String getSigAlgOID() {
+ if (sigAlgId == null)
+ return null;
+ ObjectIdentifier oid = sigAlgId.getOID();
+ return oid.toString();
+ }
+
+ /**
+ * Gets the DER encoded signature algorithm parameters from this
+ * CRL's signature algorithm. In most cases, the signature
+ * algorithm parameters are null, the parameters are usually
+ * supplied with the Public Key.
+ *
+ * @return the DER encoded signature algorithm parameters, or
+ * null if no parameters are present.
+ */
+ public byte[] getSigAlgParams() {
+ if (sigAlgId == null)
+ return null;
+ try {
+ return sigAlgId.getEncodedParams();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked CRITICAL in the
+ * CRL by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * CRL that are marked critical.
+ */
+ public Set<String> getCriticalExtensionOIDs() {
+ if (extensions == null)
+ return null;
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (ex.isCritical()) {
+ extSet.add(((ObjectIdentifier) ex.getExtensionId()).toString());
+ }
+ }
+ return extSet;
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked NON-CRITICAL in the
+ * CRL by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * CRL that are NOT marked critical.
+ */
+ public Set<String> getNonCriticalExtensionOIDs() {
+ if (extensions == null)
+ return null;
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (!ex.isCritical())
+ extSet.add(((ObjectIdentifier) ex.getExtensionId()).toString());
+ }
+ return extSet;
+ }
+
+ /**
+ * Gets the DER encoded OCTET string for the extension value
+ * (<code>extnValue</code>) identified by the passed in oid String.
+ * The <code>oid</code> string is
+ * represented by a set of positive whole number separated
+ * by ".", that means,<br>
+ * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
+ *
+ * @param oid the Object Identifier value for the extension.
+ * @return the der encoded octet string of the extension value.
+ */
+ public byte[] getExtensionValue(String oid) {
+ if (extensions == null)
+ return null;
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
+ Extension crlExt = null;
+
+ if (extAlias == null) { // may be unknown
+ ObjectIdentifier findOID = new ObjectIdentifier(oid);
+ Extension ex = null;
+ ObjectIdentifier inCertOID;
+ for (Enumeration<Extension> e = extensions.getElements(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ inCertOID = ex.getExtensionId();
+ if (inCertOID.equals(findOID)) {
+ crlExt = ex;
+ break;
+ }
+ }
+ } else
+ crlExt = extensions.get(extAlias);
+ if (crlExt == null)
+ return null;
+ byte[] extData = crlExt.getExtensionValue();
+ if (extData == null)
+ return null;
+ DerOutputStream out = new DerOutputStream();
+ out.putOctetString(extData);
+ return out.toByteArray();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public BigInteger getCRLNumber() {
+ try {
+ CRLExtensions exts = getExtensions();
+ if (exts == null)
+ return null;
+ Enumeration<Extension> e = exts.getElements();
+ while (e.hasMoreElements()) {
+ Extension ext = (Extension) e.nextElement();
+ if (ext instanceof CRLNumberExtension) {
+ CRLNumberExtension numExt = (CRLNumberExtension) ext;
+ return (BigInteger) numExt.get(CRLNumberExtension.NUMBER);
+ }
+ }
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public BigInteger getDeltaBaseCRLNumber() {
+ try {
+ CRLExtensions exts = getExtensions();
+ if (exts == null)
+ return null;
+ Enumeration<Extension> e = exts.getElements();
+ while (e.hasMoreElements()) {
+ Extension ext = (Extension) e.nextElement();
+ if (ext instanceof DeltaCRLIndicatorExtension) {
+ DeltaCRLIndicatorExtension numExt = (DeltaCRLIndicatorExtension) ext;
+ return (BigInteger) numExt.get(DeltaCRLIndicatorExtension.NUMBER);
+ }
+ }
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public boolean isDeltaCRL() {
+ try {
+ CRLExtensions exts = getExtensions();
+ if (exts == null)
+ return false;
+ Enumeration<Extension> e = exts.getElements();
+ while (e.hasMoreElements()) {
+ Extension ext = (Extension) e.nextElement();
+ if (ext instanceof DeltaCRLIndicatorExtension) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ /**
+ * Returns extensions for this impl.
+ *
+ * @param extn CRLExtensions
+ */
+ public CRLExtensions getExtensions() {
+ return extensions;
+ }
+
+ public boolean areEntriesIncluded() {
+ return entriesIncluded;
+ }
+
+ /*********************************************************************/
+ /*
+ * Parses an X.509 CRL, should be used only by constructors.
+ */
+ private void parse(DerValue val)
+ throws CRLException, IOException, X509ExtensionException {
+ parse(val, true);
+ }
+
+ private void parse(DerValue val, boolean includeEntries)
+ throws CRLException, IOException, X509ExtensionException {
+ // check if can over write the certificate
+ if (readOnly)
+ throw new CRLException("cannot over-write existing CRL");
+
+ readOnly = true;
+ DerValue seq[] = new DerValue[3];
+
+ seq[0] = val.data.getDerValue();
+ seq[1] = val.data.getDerValue();
+ seq[2] = val.data.getDerValue();
+
+ if (val.data.available() != 0)
+ throw new CRLException("signed overrun, bytes = "
+ + val.data.available());
+
+ if (seq[0].tag != DerValue.tag_Sequence)
+ throw new CRLException("signed CRL fields invalid");
+
+ sigAlgId = AlgorithmId.parse(seq[1]);
+ signature = seq[2].getBitString();
+
+ if (seq[1].data.available() != 0)
+ throw new CRLException("AlgorithmId field overrun");
+
+ if (seq[2].data.available() != 0)
+ throw new CRLException("Signature field overrun");
+
+ // the tbsCertsList
+ tbsCertList = seq[0].toByteArray();
+
+ // parse the information
+ DerInputStream derStrm = seq[0].data;
+ DerValue tmp;
+ byte nextByte;
+
+ // version (optional if v1)
+ version = 0; // by default, version = v1 == 0
+ nextByte = (byte) derStrm.peekByte();
+ if (nextByte == DerValue.tag_Integer) {
+ version = derStrm.getInteger().toInt();
+ if (version != 1) // i.e. v2
+ throw new CRLException("Invalid version");
+ }
+ tmp = derStrm.getDerValue();
+ // signature
+ {
+ AlgorithmId tmpId = AlgorithmId.parse(tmp);
+ if (!tmpId.equals(sigAlgId))
+ throw new CRLException("Signature algorithm mismatch");
+
+ infoSigAlgId = tmpId;
+ }
+ // issuer
+ issuer = new X500Name(derStrm);
+
+ // thisUpdate
+ // check if UTCTime encoded or GeneralizedTime
+
+ nextByte = (byte) derStrm.peekByte();
+ if (nextByte == DerValue.tag_UtcTime) {
+ thisUpdate = derStrm.getUTCTime();
+ } else if (nextByte == DerValue.tag_GeneralizedTime) {
+ thisUpdate = derStrm.getGeneralizedTime();
+ } else {
+ throw new CRLException("Invalid encoding for thisUpdate"
+ + " (tag=" + nextByte + ")");
+ }
+
+ if (derStrm.available() == 0)
+ return; // done parsing no more optional fields present
+
+ // nextUpdate (optional)
+ nextByte = (byte) derStrm.peekByte();
+ if (nextByte == DerValue.tag_UtcTime) {
+ nextUpdate = derStrm.getUTCTime();
+ } else if (nextByte == DerValue.tag_GeneralizedTime) {
+ nextUpdate = derStrm.getGeneralizedTime();
+ } // else it is not present
+
+ if (derStrm.available() == 0)
+ return; // done parsing no more optional fields present
+
+ // revokedCertificates (optional)
+ nextByte = (byte) derStrm.peekByte();
+ if ((nextByte == DerValue.tag_SequenceOf)
+ && (!((nextByte & 0x0c0) == 0x080))) {
+ if (includeEntries) {
+ DerValue[] badCerts = derStrm.getSequence(4);
+ for (int i = 0; i < badCerts.length; i++) {
+ RevokedCertImpl entry = new RevokedCertImpl(badCerts[i]);
+ if (entry.hasExtensions() && (version == 0))
+ throw new CRLException("Invalid encoding, extensions" +
+ " not supported in CRL v1 entries.");
+
+ revokedCerts.put(entry.getSerialNumber(),
+ (RevokedCertificate) entry);
+ }
+ } else {
+ derStrm.skipSequence(4);
+ }
+ }
+
+ if (derStrm.available() == 0)
+ return; // done parsing no extensions
+
+ // crlExtensions (optional)
+ tmp = derStrm.getDerValue();
+ if (tmp.isConstructed() && tmp.isContextSpecific((byte) 0)) {
+ if (version == 0)
+ throw new CRLException("Invalid encoding, extensions not" +
+ " supported in CRL v1.");
+ extensions = new CRLExtensions(tmp.data);
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509Cert.java b/base/util/src/netscape/security/x509/X509Cert.java
new file mode 100644
index 000000000..9ab7ba754
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509Cert.java
@@ -0,0 +1,849 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.Certificate;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Date;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * @author David Brownell
+ * @version 1.5
+ *
+ * @see CertAndKeyGen
+ * @deprecated Use the new X509Certificate class.
+ * This class is only restored for backwards compatibility.
+ */
+public class X509Cert implements Certificate, Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6968141532738786900L;
+ /* The algorithm id */
+ protected AlgorithmId algid;
+
+ /**
+ * Construct a uninitialized X509 Cert on which <a href="#decode">
+ * decode</a> must later be called (or which may be deserialized).
+ */
+ // XXX deprecated, delete this
+ public X509Cert() {
+ }
+
+ /**
+ * Unmarshals a certificate from its encoded form, parsing the
+ * encoded bytes. This form of constructor is used by agents which
+ * need to examine and use certificate contents. That is, this is
+ * one of the more commonly used constructors. Note that the buffer
+ * must include only a certificate, and no "garbage" may be left at
+ * the end. If you need to ignore data at the end of a certificate,
+ * use another constructor.
+ *
+ * @param cert the encoded bytes, with no terminatu (CONSUMED)
+ * @exception IOException when the certificate is improperly encoded.
+ */
+ public X509Cert(
+ byte cert[]) throws IOException {
+ DerValue in = new DerValue(cert);
+
+ parse(in);
+ if (in.data.available() != 0)
+ throw new CertParseError("garbage at end");
+ signedCert = cert;
+ }
+
+ /**
+ * Unmarshals a certificate from its encoded form, parsing the
+ * encoded bytes. This form of constructor is used by agents which
+ * need to examine and use certificate contents. That is, this is
+ * one of the most commonly used constructors.
+ *
+ * @param buf the buffer holding the encoded bytes
+ * @param offset the offset in the buffer where the bytes begin
+ * @param len how many bytes of certificate exist
+ *
+ * @exception IOException when the certificate is improperly encoded.
+ */
+ public X509Cert(
+ byte buf[],
+ int offset,
+ int len) throws IOException {
+ DerValue in = new DerValue(buf, offset, len);
+
+ parse(in);
+ if (in.data.available() != 0)
+ throw new CertParseError("garbage at end");
+ signedCert = new byte[len];
+ System.arraycopy(buf, offset, signedCert, 0, len);
+ }
+
+ /**
+ * Unmarshal a certificate from its encoded form, parsing a DER value.
+ * This form of constructor is used by agents which need to examine
+ * and use certificate contents.
+ *
+ * @param derVal the der value containing the encoded cert.
+ * @exception IOException when the certificate is improperly encoded.
+ */
+ public X509Cert(DerValue derVal) throws IOException {
+ parse(derVal);
+ if (derVal.data.available() != 0)
+ throw new CertParseError("garbage at end");
+ signedCert = derVal.toByteArray();
+ }
+
+ /**
+ * Partially constructs a certificate from descriptive parameters.
+ * This constructor may be used by Certificate Authority (CA) code,
+ * which later <a href="#signAndEncode">signs and encodes</a> the
+ * certificate. Also, self-signed certificates serve as CA certificates,
+ * and are sometimes used as certificate requests.
+ *
+ * <P>
+ * Until the certificate has been signed and encoded, some of the mandatory fields in the certificate will not be
+ * available via accessor functions: the serial number, issuer name and signing algorithm, and of course the signed
+ * certificate. The fields passed to this constructor are available, and must be non-null.
+ *
+ * <P>
+ * Note that the public key being signed is generally independent of the signature algorithm being used. So for
+ * example Diffie-Hellman keys (which do not support signatures) can be placed in X.509 certificates when some other
+ * signature algorithm (e.g. DSS/DSA, or one of the RSA based algorithms) is used.
+ *
+ * @see CertAndKeyGen
+ *
+ * @param subjectName the X.500 distinguished name being certified
+ * @param subjectPublicKey the public key being certified. This
+ * must be an "X509Key" implementing the "PublicKey" interface.
+ * @param notBefore the first time the certificate is valid
+ * @param notAfter the last time the certificate is valid
+ *
+ * @exception CertException if the public key is inappropriate
+ */
+ public X509Cert(
+ X500Name subjectName,
+ X509Key subjectPublicKey,
+ Date notBefore,
+ Date notAfter) throws CertException {
+ subject = subjectName;
+
+ if (!(subjectPublicKey instanceof PublicKey))
+ throw new CertException(CertException.err_INVALID_PUBLIC_KEY,
+ "Doesn't implement PublicKey interface");
+
+ /*
+ * The X509 cert API requires X509 keys, else things break.
+ */
+ pubkey = subjectPublicKey;
+ notbefore = notBefore;
+ notafter = notAfter;
+ version = 0;
+ }
+
+ /**
+ * Decode an X.509 certificate from an input stream.
+ *
+ * @param in an input stream holding at least one certificate
+ * @exception IOException when the certificate is improperly encoded.
+ */
+ public void decode(InputStream in) throws IOException {
+ DerValue val = new DerValue(in);
+
+ parse(val);
+ if (val.data.available() != 0)
+ throw new CertParseError("garbage at end");
+ signedCert = val.toByteArray();
+ }
+
+ /**
+ * Appends the certificate to an output stream.
+ *
+ * @param out an input stream to which the certificate is appended.
+ * @exception IOException when appending fails.
+ */
+ public void encode(OutputStream out) throws IOException {
+ out.write(getSignedCert());
+ }
+
+ /**
+ * Compares two certificates. This is false if the
+ * certificates are not both X.509 certs, otherwise it
+ * compares them as binary data.
+ *
+ * @param other the object being compared with this one
+ * @return true iff the certificates are equivalent
+ */
+ public boolean equals(Object other) {
+ if (other instanceof X509Cert)
+ return equals((X509Cert) other);
+ else
+ return false;
+ }
+
+ /**
+ * Compares two certificates, returning false if any data
+ * differs between the two.
+ *
+ * @param other the object being compared with this one
+ * @return true iff the certificates are equivalent
+ */
+ public boolean equals(X509Cert src) {
+ if (this == src)
+ return true;
+ if (signedCert == null || src.signedCert == null)
+ return false;
+ if (signedCert.length != src.signedCert.length)
+ return false;
+ for (int i = 0; i < signedCert.length; i++)
+ if (signedCert[i] != src.signedCert[i])
+ return false;
+ return true;
+ }
+
+ /** Returns the "X.509" format identifier. */
+ public String getFormat() // for Certificate
+ {
+ return "X.509";
+ }
+
+ /** Returns <a href="#getIssuerName">getIssuerName</a> */
+ public Principal getGuarantor() // for Certificate
+ {
+ return getIssuerName();
+ }
+
+ /** Returns <a href="#getSubjectName">getSubjectName</a> */
+ public Principal getPrincipal() {
+ return getSubjectName();
+ }
+
+ /**
+ * Throws an exception if the certificate is invalid because it is
+ * now outside of the certificate's validity period, or because it
+ * was not signed using the verification key provided. Successfully
+ * verifying a certificate does <em>not</em> indicate that one should
+ * trust the entity which it represents.
+ *
+ * <P>
+ * <em>Note that since this class represents only a single X.509
+ * certificate, it cannot know anything about the certificate chain
+ * which is used to provide the verification key and to establish trust.
+ * Other code must manage and use those cert chains.
+ *
+ * <P>For now, you must walk the cert chain being used to verify any
+ * given cert. Start at the root, which is a self-signed certificate;
+ * verify it using the key inside the certificate. Then use that to
+ * verify the next certificate in the chain, issued by that CA. In
+ * this manner, verify each certificate until you reach the particular
+ * certificate you wish to verify. You should not use a certificate
+ * if any of the verification operations for its certificate chain
+ * were unsuccessful.
+ * </em>
+ *
+ * @param issuerPublicKey the public key of the issuing CA
+ * @exception CertException when the certificate is not valid.
+ */
+ public void verify(PublicKey issuerPublicKey)
+ throws CertException {
+ Date now = new Date();
+
+ if (now.before(notbefore))
+ throw new CertException(CertException.verf_INVALID_NOTBEFORE);
+ if (now.after(notafter))
+ throw new CertException(CertException.verf_INVALID_EXPIRED);
+ if (signedCert == null)
+ throw new CertException(CertException.verf_INVALID_SIG,
+ "?? certificate is not signed yet ??");
+
+ //
+ // Verify the signature ...
+ //
+ String algName = null;
+
+ try {
+ Signature sigVerf = null;
+
+ algName = issuerSigAlg.getName();
+ sigVerf = Signature.getInstance(algName);
+ sigVerf.initVerify(issuerPublicKey);
+ sigVerf.update(rawCert, 0, rawCert.length);
+
+ if (!sigVerf.verify(signature)) {
+ throw new CertException(CertException.verf_INVALID_SIG,
+ "Signature ... by <" + issuer + "> for <" + subject + ">");
+ }
+
+ // Gag -- too many catch clauses, let most through.
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new CertException(CertException.verf_INVALID_SIG,
+ "Unsupported signature algorithm (" + algName + ")");
+
+ } catch (InvalidKeyException e) {
+ // e.printStackTrace();
+ throw new CertException(CertException.err_INVALID_PUBLIC_KEY,
+ "Algorithm (" + algName + ") rejected public key");
+
+ } catch (SignatureException e) {
+ throw new CertException(CertException.verf_INVALID_SIG,
+ "Signature by <" + issuer + "> for <" + subject + ">");
+ }
+ }
+
+ /**
+ * Creates an X.509 certificate, and signs it using the issuer
+ * passed (associating a signature algorithm and an X.500 name).
+ * This operation is used to implement the certificate generation
+ * functionality of a certificate authority.
+ *
+ * @see #getSignedCert
+ * @see #getSigner
+ * @see CertAndKeyGen
+ *
+ * @param serial the serial number of the certificate (non-null)
+ * @param issuer the certificate issuer (CA) (non-null)
+ * @return the signed certificate, as returned by getSignedCert
+ *
+ * @exception IOException if any of the data could not be encoded,
+ * or when any mandatory data was omitted
+ * @exception SignatureException on signing failures
+ */
+ public byte[]
+ encodeAndSign(
+ BigInt serial,
+ X500Signer issuer
+ ) throws IOException, SignatureException {
+ rawCert = null;
+
+ /*
+ * Get the remaining cert parameters, and make sure we have enough.
+ *
+ * We deduce version based on what attribute data are available
+ * For now, we have no attributes, so we always deduce X.509v1 !
+ */
+ version = 0;
+ serialnum = serial;
+ this.issuer = issuer.getSigner();
+ issuerSigAlg = issuer.getAlgorithmId();
+
+ if (subject == null || pubkey == null
+ || notbefore == null || notafter == null)
+ throw new IOException("not enough cert parameters");
+
+ /*
+ * Encode the raw cert, create its signature and put it
+ * into the envelope.
+ */
+ rawCert = DERencode();
+ signedCert = sign(issuer, rawCert);
+ return signedCert;
+ }
+
+ /**
+ * Returns an X500Signer that may be used to create signatures. Those
+ * signature may in turn be verified using this certificate (or a
+ * copy of it).
+ *
+ * <P>
+ * <em><b>NOTE:</b> If the private key is by itself capable of
+ * creating signatures, this fact may not be recognized at this time.
+ * Specifically, the case of DSS/DSA keys which get their algorithm
+ * parameters from higher in the certificate chain is not supportable
+ * without using an X509CertChain API, and there is no current support
+ * for other sources of algorithm parameters.</em>
+ *
+ * @param algorithm the signature algorithm to be used. Note that a
+ * given public/private key pair may support several such algorithms.
+ * @param privateKey the private key used to create the signature,
+ * which must correspond to the public key in this certificate
+ * @return the Signer object
+ *
+ * @exception NoSuchAlgorithmException if the signature
+ * algorithm is not supported
+ * @exception InvalidKeyException if either the key in the certificate,
+ * or the private key parameter, does not support the requested
+ * signature algorithm
+ */
+ public X500Signer getSigner(AlgorithmId algorithmId,
+ PrivateKey privateKey)
+ throws NoSuchAlgorithmException, InvalidKeyException {
+ String algorithm;
+ Signature sig;
+
+ if (privateKey instanceof Key) {
+ Key key = (Key) privateKey;
+ algorithm = key.getAlgorithm();
+ } else {
+ throw new InvalidKeyException("private key not a key!");
+ }
+
+ sig = Signature.getInstance(algorithmId.getName());
+
+ if (!pubkey.getAlgorithm().equals(algorithm)) {
+
+ throw new InvalidKeyException("Private key algorithm " +
+ algorithm +
+ " incompatible with certificate " +
+ pubkey.getAlgorithm());
+ }
+ sig.initSign(privateKey);
+ return new X500Signer(sig, subject);
+ }
+
+ /**
+ * Returns a signature object that may be used to verify signatures
+ * created using a specified signature algorithm and the public key
+ * contained in this certificate.
+ *
+ * <P>
+ * <em><b>NOTE:</b> If the public key in this certificate is not by
+ * itself capable of verifying signatures, this may not be recognized
+ * at this time. Specifically, the case of DSS/DSA keys which get
+ * their algorithm parameters from higher in the certificate chain
+ * is not supportable without using an X509CertChain API, and there
+ * is no current support for other sources of algorithm parameters.</em>
+ *
+ * @param algorithm the algorithm of the signature to be verified
+ * @return the Signature object
+ * @exception NoSuchAlgorithmException if the signature
+ * algorithm is not supported
+ * @exception InvalidKeyException if the key in the certificate
+ * does not support the requested signature algorithm
+ */
+ public Signature getVerifier(String algorithm)
+ throws NoSuchAlgorithmException, InvalidKeyException {
+ Signature sig;
+
+ sig = Signature.getInstance(algorithm);
+ sig.initVerify(pubkey);
+ return sig;
+ }
+
+ /**
+ * Return the signed X.509 certificate as a byte array.
+ * The bytes are in standard DER marshaled form.
+ * Null is returned in the case of a partially constructed cert.
+ */
+ public byte[] getSignedCert() {
+ return signedCert;
+ }
+
+ /**
+ * Returns the certificate's serial number.
+ * Null is returned in the case of a partially constructed cert.
+ */
+ public BigInt getSerialNumber() {
+ return serialnum;
+ }
+
+ /**
+ * Returns the subject's X.500 distinguished name.
+ */
+ public X500Name getSubjectName() {
+ return subject;
+ }
+
+ /**
+ * Returns the certificate issuer's X.500 distinguished name.
+ * Null is returned in the case of a partially constructed cert.
+ */
+ public X500Name getIssuerName() {
+ return issuer;
+ }
+
+ /**
+ * Returns the algorithm used by the issuer to sign the certificate.
+ * Null is returned in the case of a partially constructed cert.
+ */
+ public AlgorithmId getIssuerAlgorithmId() {
+ return issuerSigAlg;
+ }
+
+ /**
+ * Returns the first time the certificate is valid.
+ */
+ public Date getNotBefore() {
+ return notbefore;
+ }
+
+ /**
+ * Returns the last time the certificate is valid.
+ */
+ public Date getNotAfter() {
+ return notafter;
+ }
+
+ /**
+ * Returns the subject's public key. Note that some public key
+ * algorithms support an optional certificate generation policy
+ * where the keys in the certificates are not in themselves sufficient
+ * to perform a public key operation. Those keys need to be augmented
+ * by algorithm parameters, which the certificate generation policy
+ * chose not to place in the certificate.
+ *
+ * <P>
+ * Two such public key algorithms are: DSS/DSA, where algorithm parameters could be acquired from a CA certificate
+ * in the chain of issuers; and Diffie-Hellman, with a similar solution although the CA then needs both a
+ * Diffie-Hellman certificate and a signature capable certificate.
+ */
+ public PublicKey getPublicKey() {
+ return pubkey;
+ }
+
+ /**
+ * Returns the X.509 version number of this certificate, zero based.
+ * That is, "2" indicates an X.509 version 3 (1993) certificate,
+ * and "0" indicates X.509v1 (1988).
+ * Zero is returned in the case of a partially constructed cert.
+ */
+ public int getVersion() {
+ return version;
+ }
+
+ /**
+ * Calculates a hash code value for the object. Objects
+ * which are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+
+ for (int i = 0; i < signedCert.length; i++)
+ retval += signedCert[i] * i;
+ return retval;
+ }
+
+ /**
+ * Returns a printable representation of the certificate. This does not
+ * contain all the information available to distinguish this from any
+ * other certificate. The certificate must be fully constructed
+ * before this function may be called; in particular, if you are
+ * creating certificates you must call encodeAndSign() before calling
+ * this function.
+ */
+ public String toString() {
+ String s;
+
+ if (subject == null || pubkey == null
+ || notbefore == null || notafter == null
+ || issuer == null || issuerSigAlg == null
+ || serialnum == null)
+ throw new NullPointerException("X.509 cert is incomplete");
+
+ s = " X.509v" + (version + 1) + " certificate,\n";
+ s += " Subject is " + subject + "\n";
+ s += " Key: " + pubkey;
+ s += " Validity <" + notbefore + "> until <" + notafter + ">\n";
+ s += " Issuer is " + issuer + "\n";
+ s += " Issuer signature used " + issuerSigAlg.toString() + "\n";
+ s += " Serial number = " + serialnum + "\n";
+
+ // optional v2, v3 extras
+
+ return "[\n" + s + "]";
+ }
+
+ /**
+ * Returns a printable representation of the certificate.
+ *
+ * @param detailed true iff lots of detail is requested
+ */
+ public String toString(boolean detailed) {
+ return toString();
+ }
+
+ /*
+ * Certificate data, and its envelope
+ */
+ private byte rawCert[];
+ private byte signature[];
+ private byte signedCert[];
+
+ /*
+ * X509.v1 data (parsed)
+ */
+ private X500Name subject; // from subject
+ private X509Key pubkey;
+
+ private Date notafter; // from CA (constructor)
+ private Date notbefore;
+
+ private int version; // from CA (signAndEncode)
+ private BigInt serialnum;
+ private X500Name issuer;
+ private AlgorithmId issuerSigAlg;
+
+ /*
+ * X509.v2 extensions
+ */
+
+ /*
+ * X509.v3 extensions
+ */
+
+ /*
+ * Other extensions ... Netscape, Verisign, SET, etc
+ */
+
+ /************************************************************/
+
+ /*
+ * Cert is a SIGNED ASN.1 macro, a three elment sequence:
+ *
+ * - Data to be signed (ToBeSigned) -- the "raw" cert
+ * - Signature algorithm (SigAlgId)
+ * - The signature bits
+ *
+ * This routine unmarshals the certificate, saving the signature
+ * parts away for later verification.
+ */
+ private void parse(DerValue val)
+ throws IOException {
+ DerValue seq[] = new DerValue[3];
+
+ seq[0] = val.data.getDerValue();
+ seq[1] = val.data.getDerValue();
+ seq[2] = val.data.getDerValue();
+
+ if (val.data.available() != 0)
+ throw new CertParseError("signed overrun, bytes = "
+ + val.data.available());
+ if (seq[0].tag != DerValue.tag_Sequence)
+ throw new CertParseError("signed fields invalid");
+
+ rawCert = seq[0].toByteArray(); // XXX slow; fixme!
+
+ issuerSigAlg = AlgorithmId.parse(seq[1]);
+ signature = seq[2].getBitString();
+
+ if (seq[1].data.available() != 0) {
+ // XXX why was this error check commented out?
+ // It was originally part of the next check.
+ throw new CertParseError("algid field overrun");
+ }
+
+ if (seq[2].data.available() != 0)
+ throw new CertParseError("signed fields overrun");
+
+ /*
+ * Let's have fun parsing the cert itself.
+ */
+ DerInputStream in;
+ DerValue tmp;
+
+ in = seq[0].data;
+
+ /*
+ * Version -- this is optional (default zero). If it's there it's
+ * the first field and is specially tagged.
+ *
+ * Both branches leave "tmp" holding a value for the serial
+ * number that comes next.
+ */
+ version = 0;
+ tmp = in.getDerValue();
+ if (tmp.isConstructed() && tmp.isContextSpecific()) {
+ version = tmp.data.getInteger().toInt();
+ if (tmp.data.available() != 0)
+ throw new IOException("X.509 version, bad format");
+ tmp = in.getDerValue();
+ }
+
+ /*
+ * serial number ... an integer
+ */
+ serialnum = tmp.getInteger();
+
+ /*
+ * algorithm type for CA's signature ... needs to match the
+ * one on the envelope, and that's about it! different IDs
+ * may represent a signature attack. In general we want to
+ * inherit parameters.
+ */
+ tmp = in.getDerValue();
+ {
+ AlgorithmId algid;
+
+ algid = AlgorithmId.parse(tmp);
+
+ if (!algid.equals(issuerSigAlg))
+ throw new CertParseError("CA Algorithm mismatch!");
+
+ this.algid = algid;
+ }
+
+ /*
+ * issuer name
+ */
+ issuer = new X500Name(in);
+
+ /*
+ * validity: SEQUENCE { start date, end date }
+ */
+ tmp = in.getDerValue();
+ if (tmp.tag != DerValue.tag_Sequence)
+ throw new CertParseError("corrupt validity field");
+
+ notbefore = tmp.data.getUTCTime();
+ notafter = tmp.data.getUTCTime();
+ if (tmp.data.available() != 0)
+ throw new CertParseError("excess validity data");
+
+ /*
+ * subject name and public key
+ */
+ subject = new X500Name(in);
+
+ tmp = in.getDerValue();
+ pubkey = X509Key.parse(tmp);
+
+ /*
+ * XXX for v2 and later, a bunch of tagged options follow
+ */
+
+ if (in.available() != 0) {
+ /*
+ * Until we parse V2/V3 data ... ignore it.
+ *
+ // throw new CertParseError ("excess cert data");
+ System.out.println (
+ "@end'o'cert, optional V2/V3 data unparsed: "
+ + in.available ()
+ + " bytes"
+ );
+ */
+ }
+ }
+
+ /*
+ * Encode only the parts that will later be signed.
+ */
+ private byte[] DERencode() throws IOException {
+ DerOutputStream raw = new DerOutputStream();
+
+ encode(raw);
+ return raw.toByteArray();
+ }
+
+ /*
+ * Marshal the contents of a "raw" certificate into a DER sequence.
+ */
+ private void encode(DerOutputStream out) throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ /*
+ * encode serial number, issuer signing algorithm,
+ * and issuer name into the data we'll return
+ */
+ tmp.putInteger(serialnum);
+ issuerSigAlg.encode(tmp);
+ issuer.encode(tmp);
+
+ /*
+ * Validity is a two element sequence ... encode the
+ * elements, then wrap them into the data we'll return
+ */
+ {
+ DerOutputStream seq = new DerOutputStream();
+
+ seq.putUTCTime(notbefore);
+ seq.putUTCTime(notafter);
+ tmp.write(DerValue.tag_Sequence, seq);
+ }
+
+ /*
+ * Encode subject (principal) and associated key
+ */
+ subject.encode(tmp);
+ pubkey.encode(tmp);
+
+ /*
+ * Wrap the data; encoding of the "raw" cert is now complete.
+ */
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /*
+ * Calculate the signature of the "raw" certificate,
+ * and marshal the cert with the signature and a
+ * description of the signing algorithm.
+ */
+ private byte[] sign(X500Signer issuer, byte data[])
+ throws IOException, SignatureException {
+ /*
+ * Encode the to-be-signed data, then the algorithm used
+ * to create the signature.
+ */
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ tmp.write(data);
+ issuer.getAlgorithmId().encode(tmp);
+
+ /*
+ * Create and encode the signature itself.
+ */
+ issuer.update(data, 0, data.length);
+ signature = issuer.sign();
+ tmp.putBitString(signature);
+
+ /*
+ * Wrap the signed data in a SEQUENCE { data, algorithm, sig }
+ */
+ out.write(DerValue.tag_Sequence, tmp);
+ return out.toByteArray();
+ }
+
+ /**
+ * Serialization write ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ * (Actually they serialize as some type data from the
+ * serialization subsystem, then the cert data.)
+ */
+ private synchronized void
+ writeObject(java.io.ObjectOutputStream stream)
+ throws IOException {
+ encode(stream);
+ }
+
+ /**
+ * Serialization read ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void
+ readObject(ObjectInputStream stream)
+ throws IOException {
+ decode(stream);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509CertImpl.java b/base/util/src/netscape/security/x509/X509CertImpl.java
new file mode 100755
index 000000000..9c62b36a6
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509CertImpl.java
@@ -0,0 +1,1226 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerEncoder;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+
+/**
+ * The X509CertImpl class represents an X.509 certificate. These certificates
+ * are widely used to support authentication and other functionality in
+ * Internet security systems. Common applications include Privacy Enhanced
+ * Mail (PEM), Transport Layer Security (SSL), code signing for trusted
+ * software distribution, and Secure Electronic Transactions (SET). There
+ * is a commercial infrastructure ready to manage large scale deployments
+ * of X.509 identity certificates.
+ *
+ * <P>
+ * These certificates are managed and vouched for by <em>Certificate
+ * Authorities</em> (CAs). CAs are services which create certificates by placing data in the X.509 standard format and
+ * then digitally signing that data. Such signatures are quite difficult to forge. CAs act as trusted third parties,
+ * making introductions between agents who have no direct knowledge of each other. CA certificates are either signed by
+ * themselves, or by some other CA such as a "root" CA.
+ *
+ * <P>
+ * RFC 1422 is very informative, though it does not describe much of the recent work being done with X.509 certificates.
+ * That includes a 1996 version (X.509v3) and a variety of enhancements being made to facilitate an explosion of
+ * personal certificates used as "Internet Drivers' Licences", or with SET for credit card transactions.
+ *
+ * <P>
+ * More recent work includes the IETF PKIX Working Group efforts, especially part 1.
+ *
+ * @author Dave Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.94 97/12/10
+ * @see X509CertInfo
+ */
+public class X509CertImpl extends X509Certificate
+ implements Serializable, DerEncoder {
+ // Serialization compatibility with the X509CertImpl in x509v1.jar
+ // supporting the subset of X509Certificate on JDK1.1.x platforms.
+ static final long serialVersionUID = -2048442350420423405L;
+
+ private static final String DOT = ".";
+ /**
+ * Public attribute names.
+ */
+ public static final String NAME = "x509";
+ public static final String INFO = X509CertInfo.NAME;
+ public static final String ALG_ID = "algorithm";
+ public static final String SIGNATURE = "signature";
+ public static final String SIGNED_CERT = "signed_cert";
+
+ /**
+ * The following are defined for ease-of-use. These
+ * are the most frequently retrieved attributes.
+ */
+ // x509.info.subject.dname
+ public static final String SUBJECT_DN = NAME + DOT + INFO + DOT +
+ X509CertInfo.SUBJECT + DOT +
+ CertificateSubjectName.DN_NAME;
+ // x509.info.issuer.dname
+ public static final String ISSUER_DN = NAME + DOT + INFO + DOT +
+ X509CertInfo.ISSUER + DOT +
+ CertificateIssuerName.DN_NAME;
+ // x509.info.serialNumber.number
+ public static final String SERIAL_ID = NAME + DOT + INFO + DOT +
+ X509CertInfo.SERIAL_NUMBER + DOT +
+ CertificateSerialNumber.NUMBER;
+ // x509.info.key.value
+ public static final String PUBLIC_KEY = NAME + DOT + INFO + DOT +
+ X509CertInfo.KEY + DOT +
+ CertificateX509Key.KEY;
+
+ // x509.algorithm
+ public static final String SIG_ALG = NAME + DOT + ALG_ID;
+
+ // x509.signature
+ public static final String SIG = NAME + DOT + SIGNATURE;
+
+ // when we sign and decode we set this to true
+ // this is our means to make certificates immutable
+ private boolean readOnly = false;
+
+ // Certificate data, and its envelope
+ private byte[] signedCert;
+ protected X509CertInfo info = null;
+ protected AlgorithmId algId;
+ protected byte[] signature;
+
+ // recognized extension OIDS
+ private static final String KEY_USAGE_OID = "2.5.29.15";
+ private static final String BASIC_CONSTRAINT_OID = "2.5.29.19";
+
+ /**
+ * Default constructor.
+ */
+ public X509CertImpl() {
+ }
+
+ /**
+ * Unmarshals a certificate from its encoded form, parsing the
+ * encoded bytes. This form of constructor is used by agents which
+ * need to examine and use certificate contents. That is, this is
+ * one of the more commonly used constructors. Note that the buffer
+ * must include only a certificate, and no "garbage" may be left at
+ * the end. If you need to ignore data at the end of a certificate,
+ * use another constructor.
+ *
+ * @param certData the encoded bytes, with no trailing padding.
+ * @exception CertificateException on parsing and initialization errors.
+ */
+ public X509CertImpl(byte[] certData)
+ throws CertificateException {
+ this(certData, null);
+ }
+
+ /**
+ * As a special optimization, this constructor acts as X509CertImpl(byte[])
+ * except that it takes an X509CertInfo which it uses as a 'hint' for
+ * how to construct one field.
+ *
+ * @param certData the encode bytes, with no traiing padding
+ * @param certInfo the certInfo which has already been constructed
+ * from the certData
+ */
+
+ public X509CertImpl(byte[] certData, X509CertInfo certInfo)
+ throws CertificateException {
+
+ // setting info here causes it to skip decoding in the parse()
+ // method
+ info = certInfo;
+
+ try {
+ DerValue in = new DerValue(certData);
+
+ parse(in);
+ signedCert = certData;
+ } catch (IOException e) {
+ throw new CertificateException("Unable to initialize, " + e);
+ }
+ }
+
+ /**
+ * unmarshals an X.509 certificate from an input stream.
+ *
+ * @param in an input stream holding at least one certificate
+ * @exception CertificateException on parsing and initialization errors.
+ */
+ public X509CertImpl(InputStream in)
+ throws CertificateException {
+ try {
+ DerValue val = new DerValue(in);
+
+ parse(val);
+ signedCert = val.toByteArray();
+ } catch (IOException e) {
+ throw new CertificateException("Unable to initialize, " + e);
+ }
+ }
+
+ /**
+ * Construct an initialized X509 Certificate. The certificate is stored
+ * in raw form and has to be signed to be useful.
+ *
+ * @param certInfo the X509CertificateInfo which the Certificate is to be
+ * created from.
+ */
+ public X509CertImpl(X509CertInfo certInfo) {
+ this.info = certInfo;
+ }
+
+ /**
+ * Unmarshal a certificate from its encoded form, parsing a DER value.
+ * This form of constructor is used by agents which need to examine
+ * and use certificate contents.
+ *
+ * @param derVal the der value containing the encoded cert.
+ * @exception CertificateException on parsing and initialization errors.
+ */
+ public X509CertImpl(DerValue derVal)
+ throws CertificateException {
+ try {
+ parse(derVal);
+ signedCert = derVal.toByteArray();
+ } catch (IOException e) {
+ throw new CertificateException("Unable to initialize, " + e);
+ }
+ }
+
+ public boolean hasUnsupportedCriticalExtension() {
+ // XXX NOT IMPLEMENTED
+ return true;
+ }
+
+ /**
+ * Decode an X.509 certificate from an input stream.
+ *
+ * @param in an input stream holding at least one certificate
+ * @exception CertificateException on parsing errors.
+ * @exception IOException on other errors.
+ */
+ public void decode(InputStream in)
+ throws CertificateException, IOException {
+ DerValue val = new DerValue(in);
+
+ parse(val);
+ signedCert = val.toByteArray();
+ }
+
+ /**
+ * Appends the certificate to an output stream.
+ *
+ * @param out an input stream to which the certificate is appended.
+ * @exception CertificateEncodingException on encoding errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateEncodingException {
+ if (signedCert == null)
+ throw new CertificateEncodingException(
+ "Null certificate to encode");
+ try {
+ out.write(signedCert);
+ } catch (IOException e) {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ if (signedCert == null)
+ throw new IOException("Null certificate to encode");
+
+ out.write(signedCert);
+ }
+
+ /**
+ * Returns the encoded form of this certificate. It is
+ * assumed that each certificate type would have only a single
+ * form of encoding; for example, X.509 certificates would
+ * be encoded as ASN.1 DER.
+ *
+ * @exception CertificateEncodingException if an encoding error occurs.
+ */
+ public byte[] getEncoded() throws CertificateEncodingException {
+ if (signedCert == null)
+ throw new CertificateEncodingException(
+ "Null certificate to encode");
+ byte[] dup = new byte[signedCert.length];
+ System.arraycopy(signedCert, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ /**
+ * Throws an exception if the certificate was not signed using the
+ * verification key provided. Successfully verifying a certificate
+ * does <em>not</em> indicate that one should trust the entity which
+ * it represents.
+ *
+ * @param key the public key used for verification.
+ *
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception NoSuchProviderException if there's no default provider.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ */
+ public void verify(PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+
+ verify(key, null);
+ }
+
+ /**
+ * Throws an exception if the certificate was not signed using the
+ * verification key provided. Successfully verifying a certificate
+ * does <em>not</em> indicate that one should trust the entity which
+ * it represents.
+ *
+ * @param key the public key used for verification.
+ * @param sigProvider the name of the provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException on incorrect provider.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ */
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ if (signedCert == null) {
+ throw new CertificateEncodingException("Uninitialized certificate");
+ }
+ // Verify the signature ...
+ Signature sigVerf = null;
+
+ sigVerf = Signature.getInstance(algId.getName(), sigProvider);
+ sigVerf.initVerify(key);
+
+ byte[] rawCert = info.getEncodedInfo();
+ sigVerf.update(rawCert, 0, rawCert.length);
+
+ if (!sigVerf.verify(signature)) {
+ throw new SignatureException("Signature does not match.");
+ }
+ }
+
+ /**
+ * Creates an X.509 certificate, and signs it using the key
+ * passed (associating a signature algorithm and an X.500 name).
+ * This operation is used to implement the certificate generation
+ * functionality of a certificate authority.
+ *
+ * @param key the private key used for signing.
+ * @param algorithm the name of the signature algorithm used.
+ *
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception NoSuchProviderException if there's no default provider.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ */
+ public void sign(PrivateKey key, String algorithm)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ sign(key, algorithm, null);
+ }
+
+ /**
+ * Creates an X.509 certificate, and signs it using the key
+ * passed (associating a signature algorithm and an X.500 name).
+ * This operation is used to implement the certificate generation
+ * functionality of a certificate authority.
+ *
+ * @param key the private key used for signing.
+ * @param algorithm the name of the signature algorithm used.
+ * @param provider the name of the provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception NoSuchProviderException on incorrect provider.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ */
+ public void sign(PrivateKey key, String algorithm, String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ try {
+ if (readOnly)
+ throw new CertificateEncodingException(
+ "cannot over-write existing certificate");
+ Signature sigEngine = null;
+ if (provider == null)
+ sigEngine = Signature.getInstance(algorithm);
+ else
+ sigEngine = Signature.getInstance(algorithm, provider);
+
+ sigEngine.initSign(key);
+
+ // in case the name is reset
+ algId = AlgorithmId.get(sigEngine.getAlgorithm());
+
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ // encode certificate info
+ info.encode(tmp);
+ byte[] rawCert = tmp.toByteArray();
+
+ // encode algorithm identifier
+ algId.encode(tmp);
+
+ // Create and encode the signature itself.
+ sigEngine.update(rawCert, 0, rawCert.length);
+ signature = sigEngine.sign();
+ tmp.putBitString(signature);
+
+ // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
+ out.write(DerValue.tag_Sequence, tmp);
+ signedCert = out.toByteArray();
+ readOnly = true;
+
+ } catch (IOException e) {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * Checks that the certificate is currently valid, i.e. the current
+ * time is within the specified validity period.
+ *
+ * @exception CertificateExpiredException if the certificate has expired.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid.
+ */
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException {
+ Date date = new Date();
+ checkValidity(date);
+ }
+
+ /**
+ * Checks that the specified date is within the certificate's
+ * validity period, or basically if the certificate would be
+ * valid at the specified date/time.
+ *
+ * @param date the Date to check against to see if this certificate
+ * is valid at that date/time.
+ *
+ * @exception CertificateExpiredException if the certificate has expired
+ * with respect to the <code>date</code> supplied.
+ * @exception CertificateNotYetValidException if the certificate is not
+ * yet valid with respect to the <code>date</code> supplied.
+ */
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException {
+
+ CertificateValidity interval = null;
+ try {
+ interval = (CertificateValidity) info.get(CertificateValidity.NAME);
+ } catch (Exception e) {
+ throw new CertificateNotYetValidException("Incorrect validity period");
+ }
+ if (interval == null)
+ throw new CertificateNotYetValidException("Null validity period");
+ interval.valid(date);
+ }
+
+ /**
+ * Return the requested attribute from the certificate.
+ *
+ * @param name the name of the attribute.
+ * @exception CertificateParsingException on invalid attribute identifier.
+ */
+ public Object get(String name)
+ throws CertificateParsingException {
+ X509AttributeName attr = new X509AttributeName(name);
+ String id = attr.getPrefix();
+ if (!(id.equalsIgnoreCase(NAME))) {
+ throw new CertificateParsingException("Invalid root of "
+ + "attribute name, expected [" + NAME +
+ "], received " + "[" + id + "]");
+ }
+ attr = new X509AttributeName(attr.getSuffix());
+ id = attr.getPrefix();
+
+ if (id.equalsIgnoreCase(INFO)) {
+ if (attr.getSuffix() != null) {
+ try {
+ return info.get(attr.getSuffix());
+ } catch (IOException e) {
+ throw new CertificateParsingException(e.toString());
+ } catch (CertificateException e) {
+ throw new CertificateParsingException(e.toString());
+ }
+ } else {
+ return (info);
+ }
+ } else if (id.equalsIgnoreCase(ALG_ID)) {
+ return (algId);
+ } else if (id.equalsIgnoreCase(SIGNATURE)) {
+ return (signature);
+ } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
+ return (signedCert);
+ } else {
+ throw new CertificateParsingException("Attribute name not "
+ + "recognized or get() not allowed for the same: " + id);
+ }
+ }
+
+ /**
+ * Set the requested attribute in the certificate.
+ *
+ * @param name the name of the attribute.
+ * @param obj the value of the attribute.
+ * @exception CertificateException on invalid attribute identifier.
+ * @exception IOException on encoding error of attribute.
+ */
+ public void set(String name, Object obj)
+ throws CertificateException, IOException {
+ // check if immutable
+ if (readOnly)
+ throw new CertificateException("cannot over-write existing"
+ + " certificate");
+
+ X509AttributeName attr = new X509AttributeName(name);
+ String id = attr.getPrefix();
+ if (!(id.equalsIgnoreCase(NAME))) {
+ throw new CertificateException("Invalid root of attribute name,"
+ + " expected [" + NAME + "], received " + id);
+ }
+ attr = new X509AttributeName(attr.getSuffix());
+ id = attr.getPrefix();
+
+ if (id.equalsIgnoreCase(INFO)) {
+ if (attr.getSuffix() == null) {
+ if (!(obj instanceof X509CertInfo)) {
+ throw new CertificateException("Attribute value should"
+ + " be of type X509CertInfo.");
+ }
+ info = (X509CertInfo) obj;
+ signedCert = null; //reset this as certificate data has changed
+ } else {
+ info.set(attr.getSuffix(), obj);
+ signedCert = null; //reset this as certificate data has changed
+ }
+ } else {
+ throw new CertificateException("Attribute name not recognized or " +
+ "set() not allowed for the same: " + id);
+ }
+ }
+
+ /**
+ * Delete the requested attribute from the certificate.
+ *
+ * @param name the name of the attribute.
+ * @exception CertificateException on invalid attribute identifier.
+ * @exception IOException on other errors.
+ */
+ public void delete(String name)
+ throws CertificateException, IOException {
+ // check if immutable
+ if (readOnly)
+ throw new CertificateException("cannot over-write existing"
+ + " certificate");
+
+ X509AttributeName attr = new X509AttributeName(name);
+ String id = attr.getPrefix();
+ if (!(id.equalsIgnoreCase(NAME))) {
+ throw new CertificateException("Invalid root of attribute name,"
+ + " expected ["
+ + NAME + "], received " + id);
+ }
+ attr = new X509AttributeName(attr.getSuffix());
+ id = attr.getPrefix();
+
+ if (id.equalsIgnoreCase(INFO)) {
+ if (attr.getSuffix() != null) {
+ info = null;
+ } else {
+ info.delete(attr.getSuffix());
+ }
+ } else if (id.equalsIgnoreCase(ALG_ID)) {
+ algId = null;
+ } else if (id.equalsIgnoreCase(SIGNATURE)) {
+ signature = null;
+ } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
+ signedCert = null;
+ } else {
+ throw new CertificateException("Attribute name not recognized or " +
+ "delete() not allowed for the same: " + id);
+ }
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getElements() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(NAME + DOT + INFO);
+ elements.addElement(NAME + DOT + ALG_ID);
+ elements.addElement(NAME + DOT + SIGNATURE);
+ elements.addElement(NAME + DOT + SIGNED_CERT);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Returns a printable representation of the certificate. This does not
+ * contain all the information available to distinguish this from any
+ * other certificate. The certificate must be fully constructed
+ * before this function may be called.
+ */
+ public String toString() {
+ if (info == null || algId == null || signature == null)
+ return "";
+
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("[\n");
+ sb.append(info.toString() + "\n");
+ sb.append(" Algorithm: [" + algId.toString() + "]\n");
+
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String signaturebits = pp.toHexString(signature);
+ sb.append(" Signature:\n" + signaturebits);
+ sb.append("]");
+
+ return sb.toString();
+ }
+
+ // the strongly typed gets, as per java.security.cert.X509Certificate
+
+ /**
+ * Gets the publickey from this certificate.
+ *
+ * @return the publickey.
+ */
+ public PublicKey getPublicKey() {
+ if (info == null)
+ return null;
+ try {
+ PublicKey key = (PublicKey) info.get(CertificateX509Key.NAME
+ + DOT + CertificateX509Key.KEY);
+ return key;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the version number from the certificate.
+ *
+ * @return the version number.
+ */
+ public int getVersion() {
+ if (info == null)
+ return -1;
+ try {
+ int vers = ((Integer) info.get(CertificateVersion.NAME
+ + DOT + CertificateVersion.VERSION)).intValue();
+ return vers;
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Gets the serial number from the certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber() {
+ if (info == null)
+ return null;
+ try {
+ SerialNumber ser = (SerialNumber) info.get(
+ CertificateSerialNumber.NAME + DOT +
+ CertificateSerialNumber.NUMBER);
+ return ((BigInt) ser.getNumber()).toBigInteger();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the subject distinguished name from the certificate.
+ *
+ * @return the subject name.
+ */
+ public Principal getSubjectDN() {
+ if (info == null)
+ return null;
+ try {
+ Principal subject = (Principal) info.get(
+ CertificateSubjectName.NAME + DOT +
+ CertificateSubjectName.DN_NAME);
+ return subject;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the issuer distinguished name from the certificate.
+ *
+ * @return the issuer name.
+ */
+ public Principal getIssuerDN() {
+ if (info == null)
+ return null;
+ try {
+ Principal issuer = (Principal) info.get(
+ CertificateIssuerName.NAME + DOT +
+ CertificateIssuerName.DN_NAME);
+ return issuer;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the notBefore date from the validity period of the certificate.
+ *
+ * @return the start date of the validity period.
+ */
+ public Date getNotBefore() {
+ if (info == null)
+ return null;
+ try {
+ Date d = (Date) info.get(CertificateValidity.NAME + DOT +
+ CertificateValidity.NOT_BEFORE);
+ return d;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the notAfter date from the validity period of the certificate.
+ *
+ * @return the end date of the validity period.
+ */
+ public Date getNotAfter() {
+ if (info == null)
+ return null;
+ try {
+ Date d = (Date) info.get(CertificateValidity.NAME + DOT +
+ CertificateValidity.NOT_AFTER);
+ return d;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the DER encoded certificate informations, the <code>tbsCertificate</code> from this certificate.
+ * This can be used to verify the signature independently.
+ *
+ * @return the DER encoded certificate information.
+ * @exception CertificateEncodingException if an encoding error occurs.
+ */
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ if (info != null) {
+ return info.getEncodedInfo();
+ } else
+ throw new CertificateEncodingException("Uninitialized certificate");
+ }
+
+ /**
+ * Gets the raw Signature bits from the certificate.
+ *
+ * @return the signature.
+ */
+ public byte[] getSignature() {
+ if (signature == null)
+ return null;
+ byte[] dup = new byte[signature.length];
+ System.arraycopy(signature, 0, dup, 0, dup.length);
+ return dup;
+ }
+
+ /**
+ * Gets the signature algorithm name for the certificate
+ * signature algorithm.
+ * For example, the string "SHA-1/DSA" or "DSS".
+ *
+ * @return the signature algorithm name.
+ */
+ public String getSigAlgName() {
+ if (algId == null)
+ return null;
+ return (algId.getName());
+ }
+
+ /**
+ * Gets the signature algorithm OID string from the certificate.
+ * For example, the string "1.2.840.10040.4.3"
+ *
+ * @return the signature algorithm oid string.
+ */
+ public String getSigAlgOID() {
+ if (algId == null)
+ return null;
+ ObjectIdentifier oid = algId.getOID();
+ return (oid.toString());
+ }
+
+ /**
+ * Gets the DER encoded signature algorithm parameters from this
+ * certificate's signature algorithm.
+ *
+ * @return the DER encoded signature algorithm parameters, or
+ * null if no parameters are present.
+ */
+ public byte[] getSigAlgParams() {
+ if (algId == null)
+ return null;
+ try {
+ return algId.getEncodedParams();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the Issuer Unique Identity from the certificate.
+ *
+ * @return the Issuer Unique Identity.
+ */
+ public boolean[] getIssuerUniqueID() {
+ if (info == null)
+ return null;
+ try {
+ UniqueIdentity id = (UniqueIdentity) info.get(
+ CertificateIssuerUniqueIdentity.NAME
+ + DOT + CertificateIssuerUniqueIdentity.ID);
+ if (id == null)
+ return null;
+ else
+ return (id.getId());
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the Subject Unique Identity from the certificate.
+ *
+ * @return the Subject Unique Identity.
+ */
+ public boolean[] getSubjectUniqueID() {
+ if (info == null)
+ return null;
+ try {
+ UniqueIdentity id = (UniqueIdentity) info.get(
+ CertificateSubjectUniqueIdentity.NAME
+ + DOT + CertificateSubjectUniqueIdentity.ID);
+ if (id == null)
+ return null;
+ else
+ return (id.getId());
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked CRITICAL in the
+ * certificate by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * certificate that are marked critical.
+ */
+ public Set<String> getCriticalExtensionOIDs() {
+ if (info == null)
+ return null;
+ try {
+ CertificateExtensions exts = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ if (exts == null)
+ return null;
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = exts.getAttributes(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (ex.isCritical())
+ extSet.add(((ObjectIdentifier) ex.getExtensionId()).toString());
+ }
+ return extSet;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets a Set of the extension(s) marked NON-CRITICAL in the
+ * certificate by OID strings.
+ *
+ * @return a set of the extension oid strings in the
+ * certificate that are NOT marked critical.
+ */
+ public Set<String> getNonCriticalExtensionOIDs() {
+ if (info == null)
+ return null;
+ try {
+ CertificateExtensions exts = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ if (exts == null)
+ return null;
+
+ Set<String> extSet = new LinkedHashSet<String>();
+ Extension ex;
+ for (Enumeration<Extension> e = exts.getAttributes(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ if (!ex.isCritical())
+ extSet.add(((ObjectIdentifier) ex.getExtensionId()).toString());
+ }
+ return extSet;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public Extension getExtension(String oid) {
+ try {
+ CertificateExtensions exts = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ if (exts == null)
+ return null;
+ ObjectIdentifier findOID = new ObjectIdentifier(oid);
+ Extension ex = null;
+ ;
+ ObjectIdentifier inCertOID;
+ for (Enumeration<Extension> e = exts.getAttributes(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ inCertOID = ex.getExtensionId();
+ if (inCertOID.equals(findOID)) {
+ return ex;
+ }
+ }
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Gets the DER encoded extension identified by the passed
+ * in oid String.
+ *
+ * @param oid the Object Identifier value for the extension.
+ */
+ public byte[] getExtensionValue(String oid) {
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
+ Extension certExt = null;
+
+ if (extAlias == null) { // may be unknown
+ // get the extensions, search thru' for this oid
+ CertificateExtensions exts = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ if (exts == null)
+ return null;
+
+ ObjectIdentifier findOID = new ObjectIdentifier(oid);
+ Extension ex = null;
+ ;
+ ObjectIdentifier inCertOID;
+ for (Enumeration<Extension> e = exts.getAttributes(); e.hasMoreElements();) {
+ ex = e.nextElement();
+ inCertOID = ex.getExtensionId();
+ if (inCertOID.equals(findOID)) {
+ certExt = ex;
+ break;
+ }
+ }
+ } else { // there's sub-class that can handle this extension
+ certExt = (Extension) this.get(extAlias);
+ }
+ if (certExt == null)
+ return null;
+ byte[] extData = certExt.getExtensionValue();
+ if (extData == null)
+ return null;
+
+ DerOutputStream out = new DerOutputStream();
+ out.putOctetString(extData);
+ return out.toByteArray();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get a boolean array representing the bits of the KeyUsage extension,
+ * (oid = 2.5.29.15).
+ *
+ * @return the bit values of this extension as an array of booleans.
+ */
+ public boolean[] getKeyUsage() {
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(
+ KEY_USAGE_OID));
+ if (extAlias == null)
+ return null;
+
+ KeyUsageExtension certExt = (KeyUsageExtension) this.get(extAlias);
+ if (certExt == null)
+ return null;
+
+ return certExt.getBits();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get the certificate constraints path length from the
+ * the critical BasicConstraints extension, (oid = 2.5.29.19).
+ *
+ * @return the length of the constraint.
+ */
+ public int getBasicConstraints() {
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(
+ BASIC_CONSTRAINT_OID));
+ if (extAlias == null)
+ return -1;
+ BasicConstraintsExtension certExt =
+ (BasicConstraintsExtension) this.get(extAlias);
+ if (certExt == null)
+ return -1;
+
+ if (((Boolean) certExt.get(BasicConstraintsExtension.IS_CA)).booleanValue() == true)
+ return ((Integer) certExt.get(
+ BasicConstraintsExtension.PATH_LEN)).intValue();
+ else
+ return -1;
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ public boolean getBasicConstraintsIsCA() {
+ boolean isCA = false;
+ try {
+ String extAlias = OIDMap.getName(new ObjectIdentifier(
+ BASIC_CONSTRAINT_OID));
+ if (extAlias == null)
+ return false;
+
+ BasicConstraintsExtension certExt =
+ (BasicConstraintsExtension) this.get(extAlias);
+ if (certExt == null)
+ return false;
+
+ isCA = ((Boolean) certExt.get(BasicConstraintsExtension.IS_CA)).booleanValue();
+ } catch (Exception e) {
+ return false;
+ }
+ return isCA;
+ }
+
+ /************************************************************/
+
+ /*
+ * Cert is a SIGNED ASN.1 macro, a three elment sequence:
+ *
+ * - Data to be signed (ToBeSigned) -- the "raw" cert
+ * - Signature algorithm (SigAlgId)
+ * - The signature bits
+ *
+ * This routine unmarshals the certificate, saving the signature
+ * parts away for later verification.
+ */
+ private void parse(DerValue val) throws CertificateException, IOException {
+ // check if can over write the certificate
+ if (readOnly)
+ throw new CertificateParsingException(
+ "cannot over-write existing certificate");
+
+ readOnly = true;
+ DerValue seq[] = new DerValue[3];
+
+ seq[0] = val.data.getDerValue();
+ seq[1] = val.data.getDerValue();
+ seq[2] = val.data.getDerValue();
+
+ if (val.data.available() != 0) {
+ throw new CertificateParsingException("signed overrun, bytes = "
+ + val.data.available());
+ }
+ if (seq[0].tag != DerValue.tag_Sequence) {
+ throw new CertificateParsingException("signed fields invalid");
+ }
+
+ algId = AlgorithmId.parse(seq[1]);
+ signature = seq[2].getBitString();
+
+ if (seq[1].data.available() != 0) {
+ throw new CertificateParsingException("algid field overrun");
+ }
+ if (seq[2].data.available() != 0)
+ throw new CertificateParsingException("signed fields overrun");
+
+ // The CertificateInfo
+ if (info == null) {
+ info = new X509CertInfo(seq[0]);
+ }
+ }
+
+ /**
+ * Serialization write ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ * (Actually they serialize as some type data from the
+ * serialization subsystem, then the cert data.)
+ */
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws CertificateException, IOException {
+ encode(stream);
+ }
+
+ /**
+ * Serialization read ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void readObject(ObjectInputStream stream)
+ throws CertificateException, IOException {
+ decode(stream);
+ }
+
+ protected static class CertificateRep1 implements java.io.Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5207881613631592409L;
+ private String type1;
+ private byte[] data1;
+
+ /**
+ * Construct the alternate Certificate class with the Certificate
+ * type and Certificate encoding bytes.
+ *
+ * <p>
+ *
+ * @param type the standard name of the Certificate type.
+ * <p>
+ *
+ * @param data the Certificate data.
+ */
+ protected CertificateRep1(String type, byte[] data) {
+ this.type1 = type;
+ this.data1 = data;
+ }
+
+ /**
+ * Resolve the Certificate Object.
+ *
+ * <p>
+ *
+ * @return the resolved Certificate Object.
+ *
+ * @throws java.io.ObjectStreamException if the Certificate could not
+ * be resolved.
+ */
+ protected Object readResolve() throws java.io.ObjectStreamException {
+ try {
+ @SuppressWarnings("unused")
+ CertificateFactory cf = CertificateFactory.getInstance(type1); // check for errors
+ return new X509CertImpl(data1);
+
+ /*
+ return cf.generateCertificate
+ (new java.io.ByteArrayInputStream(data1));
+ */
+ } catch (CertificateException e) {
+ throw new java.io.NotSerializableException("java.security.cert.Certificate: " +
+ type1 +
+ ": " +
+ e.getMessage());
+ }
+ }
+
+ }
+
+ protected Object writeReplace() throws java.io.ObjectStreamException {
+ try {
+ return new CertificateRep1("X.509", getEncoded());
+ } catch (CertificateException e) {
+ throw new java.io.NotSerializableException("java.security.cert.Certificate: " +
+ "X.509" +
+ ": " +
+ e.getMessage());
+ }
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509CertInfo.java b/base/util/src/netscape/security/x509/X509CertInfo.java
new file mode 100644
index 000000000..4777cd958
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509CertInfo.java
@@ -0,0 +1,964 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * The X509CertInfo class represents X.509 certificate information.
+ *
+ * <P>
+ * X.509 certificates have several base data elements, including:
+ * <UL>
+ *
+ * <LI>The <em>Subject Name</em>, an X.500 Distinguished Name for the entity (subject) for which the certificate was
+ * issued.
+ *
+ * <LI>The <em>Subject Public Key</em>, the public key of the subject. This is one of the most important parts of the
+ * certificate.
+ *
+ * <LI>The <em>Validity Period</em>, a time period (e.g. six months) within which the certificate is valid (unless
+ * revoked).
+ *
+ * <LI>The <em>Issuer Name</em>, an X.500 Distinguished Name for the Certificate Authority (CA) which issued the
+ * certificate.
+ *
+ * <LI>A <em>Serial Number</em> assigned by the CA, for use in certificate revocation and other applications.
+ *
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ * @version 1.16
+ * @see CertAttrSet
+ * @see Serializable
+ * @see X509CertImpl
+ */
+public class X509CertInfo implements CertAttrSet, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5094073467876311577L;
+ /**
+ * Identifier for this attribute, to be used with the
+ * get, set, delete methods of Certificate, x509 type.
+ */
+ public static final String IDENT = "x509.info";
+ // Certificate attribute names
+ public static final String NAME = "info";
+ public static final String VERSION = CertificateVersion.NAME;
+ public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
+ public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
+ public static final String ISSUER = CertificateIssuerName.NAME;
+ public static final String VALIDITY = CertificateValidity.NAME;
+ public static final String SUBJECT = CertificateSubjectName.NAME;
+ public static final String KEY = CertificateX509Key.NAME;
+ public static final String ISSUER_ID = CertificateIssuerUniqueIdentity.NAME;
+ public static final String SUBJECT_ID = CertificateSubjectUniqueIdentity.NAME;
+ public static final String EXTENSIONS = CertificateExtensions.NAME;
+
+ // X509.v1 data
+ protected CertificateVersion version = new CertificateVersion();
+ protected CertificateSerialNumber serialNum = null;
+ protected CertificateAlgorithmId algId = null;
+ protected CertificateIssuerName issuer = null;
+ protected CertificateValidity interval = null;
+ protected CertificateSubjectName subject = null;
+ protected CertificateX509Key pubKey = null;
+
+ // X509.v2 & v3 extensions
+ protected CertificateIssuerUniqueIdentity issuerUniqueId = null;
+ protected CertificateSubjectUniqueIdentity subjectUniqueId = null;
+
+ // X509.v3 extensions
+ protected CertificateExtensions extensions = null;
+
+ // Attribute numbers for internal manipulation
+ private static final int ATTR_VERSION = 1;
+ private static final int ATTR_SERIAL = 2;
+ private static final int ATTR_ALGORITHM = 3;
+ private static final int ATTR_ISSUER = 4;
+ private static final int ATTR_VALIDITY = 5;
+ private static final int ATTR_SUBJECT = 6;
+ private static final int ATTR_KEY = 7;
+ private static final int ATTR_ISSUER_ID = 8;
+ private static final int ATTR_SUBJECT_ID = 9;
+ private static final int ATTR_EXTENSIONS = 10;
+
+ // DER encoded CertificateInfo data
+ private byte[] rawCertInfo = null;
+
+ // The certificate attribute name to integer mapping stored here
+ private static final Hashtable<String, Integer> map = new Hashtable<String, Integer>();
+ static {
+ map.put(VERSION, Integer.valueOf(ATTR_VERSION));
+ map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL));
+ map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM));
+ map.put(ISSUER, Integer.valueOf(ATTR_ISSUER));
+ map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY));
+ map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT));
+ map.put(KEY, Integer.valueOf(ATTR_KEY));
+ map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID));
+ map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID));
+ map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS));
+ }
+
+ /**
+ * Construct an uninitialized X509CertInfo on which <a href="#decode">
+ * decode</a> must later be called (or which may be deserialized).
+ */
+ public X509CertInfo() {
+ }
+
+ /**
+ * Unmarshals a certificate from its encoded form, parsing the
+ * encoded bytes. This form of constructor is used by agents which
+ * need to examine and use certificate contents. That is, this is
+ * one of the more commonly used constructors. Note that the buffer
+ * must include only a certificate, and no "garbage" may be left at
+ * the end. If you need to ignore data at the end of a certificate,
+ * use another constructor.
+ *
+ * @param cert the encoded bytes, with no trailing data.
+ * @exception CertificateParsingException on parsing errors.
+ */
+ public X509CertInfo(byte[] cert) throws CertificateParsingException {
+ try {
+ DerValue in = new DerValue(cert);
+
+ parse(in);
+ } catch (IOException e) {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * Unmarshal a certificate from its encoded form, parsing a DER value.
+ * This form of constructor is used by agents which need to examine
+ * and use certificate contents.
+ *
+ * @param derVal the der value containing the encoded cert.
+ * @exception CertificateParsingException on parsing errors.
+ */
+ public X509CertInfo(DerValue derVal) throws CertificateParsingException {
+ try {
+ parse(derVal);
+ } catch (IOException e) {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * Decode an X.509 certificate from an input stream.
+ *
+ * @param in an input stream holding at least one certificate
+ * @exception CertificateParsingException on decoding errors.
+ * @exception IOException on other errors.
+ */
+ public void decode(InputStream in)
+ throws CertificateParsingException, IOException {
+ DerValue val = new DerValue(in);
+
+ parse(val);
+ }
+
+ /**
+ * Appends the certificate to an output stream.
+ *
+ * @param out an output stream to which the certificate is appended.
+ * @exception CertificateException on encoding errors.
+ * @exception IOException on other errors.
+ */
+ public void encode(OutputStream out)
+ throws CertificateException, IOException {
+ encode(out, false);
+ }
+
+ /**
+ * Appends the certificate to an output stream.
+ *
+ * @param out An output stream to which the certificate is appended.
+ * @param ignoreCache Whether to ignore the internal cache when encoding.
+ * (the cache can easily become out of date).
+ */
+ public void encode(OutputStream out, boolean ignoreCache)
+ throws IOException, CertificateException {
+ if (ignoreCache || (rawCertInfo == null)) {
+ DerOutputStream tmp = new DerOutputStream();
+ emit(tmp);
+ rawCertInfo = tmp.toByteArray();
+ }
+ out.write(rawCertInfo);
+ }
+
+ /**
+ * Return an enumeration of names of attributes existing within this
+ * attribute.
+ */
+ public Enumeration<String> getAttributeNames() {
+ Vector<String> elements = new Vector<String>();
+ elements.addElement(VERSION);
+ elements.addElement(SERIAL_NUMBER);
+ elements.addElement(ALGORITHM_ID);
+ elements.addElement(ISSUER);
+ elements.addElement(VALIDITY);
+ elements.addElement(SUBJECT);
+ elements.addElement(KEY);
+ elements.addElement(ISSUER_ID);
+ elements.addElement(SUBJECT_ID);
+ elements.addElement(EXTENSIONS);
+
+ return (elements.elements());
+ }
+
+ /**
+ * Return the name of this attribute.
+ */
+ public String getName() {
+ return (NAME);
+ }
+
+ /**
+ * Returns the encoded certificate info.
+ *
+ * @exception CertificateEncodingException on encoding information errors.
+ */
+ public byte[] getEncodedInfo() throws CertificateEncodingException {
+ return getEncodedInfo(false);
+ }
+
+ public byte[] getEncodedInfo(boolean ignoreCache) throws CertificateEncodingException {
+ try {
+ if (ignoreCache || (rawCertInfo == null)) {
+ DerOutputStream tmp = new DerOutputStream();
+ emit(tmp);
+ rawCertInfo = tmp.toByteArray();
+ }
+ byte[] dup = new byte[rawCertInfo.length];
+ System.arraycopy(rawCertInfo, 0, dup, 0, dup.length);
+ return dup;
+ } catch (IOException e) {
+ throw new CertificateEncodingException(e.toString());
+ } catch (CertificateException e) {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * Compares two X509CertInfo objects. This is false if the
+ * certificates are not both X.509 certs, otherwise it
+ * compares them as binary data.
+ *
+ * @param other the object being compared with this one
+ * @return true iff the certificates are equivalent
+ */
+ public boolean equals(Object other) {
+ if (other instanceof X509CertInfo) {
+ return equals((X509CertInfo) other);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Compares two certificates, returning false if any data
+ * differs between the two.
+ *
+ * @param other the object being compared with this one
+ * @return true iff the certificates are equivalent
+ */
+ public boolean equals(X509CertInfo other) {
+ if (this == other) {
+ return (true);
+ } else if (rawCertInfo == null || other.rawCertInfo == null) {
+ return (false);
+ } else if (rawCertInfo.length != other.rawCertInfo.length) {
+ return (false);
+ }
+ for (int i = 0; i < rawCertInfo.length; i++) {
+ if (rawCertInfo[i] != other.rawCertInfo[i]) {
+ return (false);
+ }
+ }
+ return (true);
+ }
+
+ /**
+ * Calculates a hash code value for the object. Objects
+ * which are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+
+ for (int i = 1; i < rawCertInfo.length; i++) {
+ retval += rawCertInfo[i] * i;
+ }
+ return (retval);
+ }
+
+ /**
+ * Returns a printable representation of the certificate.
+ */
+ public String toString() {
+
+ if (subject == null || pubKey == null || interval == null
+ || issuer == null || algId == null || serialNum == null) {
+ throw new NullPointerException("X.509 cert is incomplete");
+ }
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("[\n");
+ sb.append(" " + version.toString() + "\n");
+ sb.append(" Subject: " + subject.toString() + "\n");
+ sb.append(" Signature Algorithm: " + algId.toString() + "\n");
+ sb.append(" Key: " + pubKey.toString() + "\n");
+ sb.append(" " + interval.toString() + "\n");
+ sb.append(" Issuer: " + issuer.toString() + "\n");
+ sb.append(" " + serialNum.toString() + "\n");
+
+ // optional v2, v3 extras
+ if (issuerUniqueId != null) {
+ sb.append(" Issuer Id:\n" + issuerUniqueId.toString() + "\n");
+ }
+ if (subjectUniqueId != null) {
+ sb.append(" Subject Id:\n" + subjectUniqueId.toString() + "\n");
+ }
+ if (extensions != null) {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ for (int i = 0; i < extensions.size(); i++) {
+ sb.append(" Extension[" + i + "] = ");
+ Extension ext = (Extension) extensions.elementAt(i);
+ try {
+ if (OIDMap.getClass(ext.getExtensionId()) == null) {
+ sb.append(ext.toString());
+ byte[] extValue = ext.getExtensionValue();
+ if (extValue != null) {
+ DerOutputStream out = new DerOutputStream();
+ out.putOctetString(extValue);
+ extValue = out.toByteArray();
+ String extValuebits = pp.toHexString(extValue);
+ sb.append("Extension unknown: "
+ + "DER encoded OCTET string =\n"
+ + extValuebits);
+ }
+ } else
+ sb.append(ext.toString()); //sub-class exists
+ } catch (Exception e) {
+ sb.append(", Error parsing this extension");
+ }
+ }
+ }
+ sb.append("\n]");
+ return sb.toString();
+ }
+
+ /**
+ * Set the certificate attribute.
+ *
+ * @param name the name of the Certificate attribute.
+ * @param val the value of the Certificate attribute.
+ * @exception CertificateException on invalid attributes.
+ * @exception IOException on other errors.
+ */
+ public void set(String name, Object val)
+ throws CertificateException, IOException {
+ X509AttributeName attrName = new X509AttributeName(name);
+
+ int attr = attributeMap(attrName.getPrefix());
+ if (attr == 0) {
+ throw new CertificateException("Attribute name not recognized: "
+ + name);
+ }
+ // set rawCertInfo to null, so that we are forced to re-encode
+ rawCertInfo = null;
+
+ switch (attr) {
+ case ATTR_VERSION:
+ if (attrName.getSuffix() == null) {
+ setVersion(val);
+ } else {
+ version.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_SERIAL:
+ if (attrName.getSuffix() == null) {
+ setSerialNumber(val);
+ } else {
+ serialNum.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_ALGORITHM:
+ if (attrName.getSuffix() == null) {
+ setAlgorithmId(val);
+ } else {
+ algId.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_ISSUER:
+ if (attrName.getSuffix() == null) {
+ setIssuer(val);
+ } else {
+ issuer.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_VALIDITY:
+ if (attrName.getSuffix() == null) {
+ setValidity(val);
+ } else {
+ interval.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_SUBJECT:
+ if (attrName.getSuffix() == null) {
+ setSubject(val);
+ } else {
+ subject.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_KEY:
+ if (attrName.getSuffix() == null) {
+ setKey(val);
+ } else {
+ pubKey.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_ISSUER_ID:
+ if (attrName.getSuffix() == null) {
+ setIssuerUniqueId(val);
+ } else {
+ issuerUniqueId.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_SUBJECT_ID:
+ if (attrName.getSuffix() == null) {
+ setSubjectUniqueId(val);
+ } else {
+ subjectUniqueId.set(attrName.getSuffix(), val);
+ }
+ break;
+
+ case ATTR_EXTENSIONS:
+ if (attrName.getSuffix() == null) {
+ setExtensions(val);
+ } else {
+ extensions.set(attrName.getSuffix(), val);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Delete the certificate attribute.
+ *
+ * @param name the name of the Certificate attribute.
+ * @exception CertificateException on invalid attributes.
+ * @exception IOException on other errors.
+ */
+ public void delete(String name)
+ throws CertificateException, IOException {
+ X509AttributeName attrName = new X509AttributeName(name);
+
+ int attr = attributeMap(attrName.getPrefix());
+ if (attr == 0) {
+ throw new CertificateException("Attribute name not recognized: "
+ + name);
+ }
+ // set rawCertInfo to null, so that we are forced to re-encode
+ rawCertInfo = null;
+
+ switch (attr) {
+ case ATTR_VERSION:
+ if (attrName.getSuffix() == null) {
+ version = null;
+ } else {
+ version.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_SERIAL):
+ if (attrName.getSuffix() == null) {
+ serialNum = null;
+ } else {
+ serialNum.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_ALGORITHM):
+ if (attrName.getSuffix() == null) {
+ algId = null;
+ } else {
+ algId.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_ISSUER):
+ if (attrName.getSuffix() == null) {
+ issuer = null;
+ } else {
+ issuer.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_VALIDITY):
+ if (attrName.getSuffix() == null) {
+ interval = null;
+ } else {
+ interval.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_SUBJECT):
+ if (attrName.getSuffix() == null) {
+ subject = null;
+ } else {
+ subject.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_KEY):
+ if (attrName.getSuffix() == null) {
+ pubKey = null;
+ } else {
+ pubKey.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_ISSUER_ID):
+ if (attrName.getSuffix() == null) {
+ issuerUniqueId = null;
+ } else {
+ issuerUniqueId.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_SUBJECT_ID):
+ if (attrName.getSuffix() == null) {
+ subjectUniqueId = null;
+ } else {
+ subjectUniqueId.delete(attrName.getSuffix());
+ }
+ break;
+ case (ATTR_EXTENSIONS):
+ if (attrName.getSuffix() == null) {
+ extensions = null;
+ } else {
+ extensions.delete(attrName.getSuffix());
+ }
+ break;
+ }
+ }
+
+ /**
+ * Get the certificate attribute.
+ *
+ * @param name the name of the Certificate attribute.
+ *
+ * @exception CertificateException on invalid attributes.
+ * @exception IOException on other errors.
+ */
+ public Object get(String name)
+ throws CertificateException, IOException {
+ X509AttributeName attrName = new X509AttributeName(name);
+
+ int attr = attributeMap(attrName.getPrefix());
+ if (attr == 0) {
+ throw new CertificateParsingException(
+ "Attribute name not recognized: " + name);
+ }
+
+ switch (attr) {
+ case (ATTR_VERSION):
+ if (attrName.getSuffix() == null) {
+ return (version);
+ } else {
+ return (version.get(attrName.getSuffix()));
+ }
+ case (ATTR_SERIAL):
+ if (attrName.getSuffix() == null) {
+ return (serialNum);
+ } else {
+ return (serialNum.get(attrName.getSuffix()));
+ }
+ case (ATTR_ALGORITHM):
+ if (attrName.getSuffix() == null) {
+ return (algId);
+ } else {
+ return (algId.get(attrName.getSuffix()));
+ }
+ case (ATTR_ISSUER):
+ if (attrName.getSuffix() == null) {
+ return (issuer);
+ } else {
+ return (issuer.get(attrName.getSuffix()));
+ }
+ case (ATTR_VALIDITY):
+ if (attrName.getSuffix() == null) {
+ return (interval);
+ } else {
+ return (interval.get(attrName.getSuffix()));
+ }
+ case (ATTR_SUBJECT):
+ if (attrName.getSuffix() == null) {
+ return (subject);
+ } else {
+ return (subject.get(attrName.getSuffix()));
+ }
+ case (ATTR_KEY):
+ if (attrName.getSuffix() == null) {
+ return (pubKey);
+ } else {
+ return (pubKey.get(attrName.getSuffix()));
+ }
+ case (ATTR_ISSUER_ID):
+ if (attrName.getSuffix() == null) {
+ return (issuerUniqueId);
+ } else {
+ if (issuerUniqueId == null)
+ return null;
+ else
+ return (issuerUniqueId.get(attrName.getSuffix()));
+ }
+ case (ATTR_SUBJECT_ID):
+ if (attrName.getSuffix() == null) {
+ return (subjectUniqueId);
+ } else {
+ if (subjectUniqueId == null)
+ return null;
+ else
+ return (subjectUniqueId.get(attrName.getSuffix()));
+ }
+ case (ATTR_EXTENSIONS):
+ if (attrName.getSuffix() == null) {
+ return (extensions);
+ } else {
+ if (extensions == null)
+ return null;
+ else
+ return (extensions.get(attrName.getSuffix()));
+ }
+ }
+ return null;
+ }
+
+ /*
+ * This routine unmarshals the certificate information.
+ */
+ private void parse(DerValue val)
+ throws CertificateParsingException, IOException {
+ DerInputStream in;
+ DerValue tmp;
+
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new CertificateParsingException("signed fields invalid");
+ }
+ rawCertInfo = val.toByteArray();
+
+ in = val.data;
+
+ // Version
+ tmp = in.getDerValue();
+ if (tmp.isContextSpecific((byte) 0)) {
+ version = new CertificateVersion(tmp);
+ tmp = in.getDerValue();
+ }
+
+ // Serial number ... an integer
+ serialNum = new CertificateSerialNumber(tmp);
+
+ // Algorithm Identifier
+ algId = new CertificateAlgorithmId(in);
+
+ // Issuer name
+ issuer = new CertificateIssuerName(in);
+
+ // validity: SEQUENCE { start date, end date }
+ interval = new CertificateValidity(in);
+
+ // subject name
+ subject = new CertificateSubjectName(in);
+
+ // public key
+ pubKey = new CertificateX509Key(in);
+
+ // If more data available, make sure version is not v1.
+ if (in.available() != 0) {
+ if (version.compare(CertificateVersion.V1) == 0) {
+ throw new CertificateParsingException("excess cert data");
+ }
+ } else {
+ return;
+ }
+
+ // Get the issuerUniqueId if present
+ tmp = in.getDerValue();
+ if (tmp.isContextSpecific((byte) 1)) {
+ issuerUniqueId = new CertificateIssuerUniqueIdentity(tmp);
+ if (in.available() == 0) {
+ return;
+ }
+ tmp = in.getDerValue();
+ }
+
+ // Get the subjectUniqueId if present.
+ if (tmp.isContextSpecific((byte) 2)) {
+ subjectUniqueId = new CertificateSubjectUniqueIdentity(tmp);
+ if (in.available() == 0) {
+ return;
+ }
+ tmp = in.getDerValue();
+ }
+
+ // Get the extensions.
+ if (version.compare(CertificateVersion.V3) != 0) {
+ throw new CertificateParsingException("excess cert data");
+ }
+ if (tmp.isConstructed() && tmp.isContextSpecific((byte) 3)) {
+ extensions = new CertificateExtensions(tmp.data);
+ }
+ }
+
+ /*
+ * Marshal the contents of a "raw" certificate into a DER sequence.
+ */
+ private void emit(DerOutputStream out)
+ throws CertificateException, IOException {
+ DerOutputStream tmp = new DerOutputStream();
+
+ // version number, iff not V1
+ version.encode(tmp);
+
+ // Encode serial number, issuer signing algorithm, issuer name
+ // and validity
+ serialNum.encode(tmp);
+ algId.encode(tmp);
+ issuer.encode(tmp);
+ interval.encode(tmp);
+
+ // Encode subject (principal) and associated key
+ subject.encode(tmp);
+ pubKey.encode(tmp);
+
+ // Encode issuerUniqueId & subjectUniqueId.
+ if (issuerUniqueId != null) {
+ issuerUniqueId.encode(tmp);
+ }
+ if (subjectUniqueId != null) {
+ subjectUniqueId.encode(tmp);
+ }
+
+ // Write all the extensions.
+ if (extensions != null) {
+ extensions.encode(tmp);
+ }
+
+ // Wrap the data; encoding of the "raw" cert is now complete.
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /**
+ * Serialization write ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ * (Actually they serialize as some type data from the
+ * serialization subsystem, then the cert data.)
+ */
+ private synchronized void writeObject(ObjectOutputStream stream)
+ throws CertificateException, IOException {
+ encode(stream);
+ }
+
+ /**
+ * Serialization read ... X.509 certificates serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void readObject(ObjectInputStream stream)
+ throws CertificateException, IOException {
+ decode(stream);
+ }
+
+ /**
+ * Returns the integer attribute number for the passed attribute name.
+ */
+ private int attributeMap(String name) {
+ Integer num = map.get(name);
+ if (num == null) {
+ return (0);
+ }
+ return (num.intValue());
+ }
+
+ /**
+ * Set the version number of the certificate.
+ *
+ * @param val the Object class value for the Extensions
+ * @exception CertificateException on invalid data.
+ */
+ private void setVersion(Object val) throws CertificateException {
+ if (!(val instanceof CertificateVersion)) {
+ throw new CertificateException("Version class type invalid.");
+ }
+ version = (CertificateVersion) val;
+ }
+
+ /**
+ * Set the serial number of the certificate.
+ *
+ * @param val the Object class value for the CertificateSerialNumber
+ * @exception CertificateException on invalid data.
+ */
+ private void setSerialNumber(Object val) throws CertificateException {
+ if (!(val instanceof CertificateSerialNumber)) {
+ throw new CertificateException("SerialNumber class type invalid.");
+ }
+ serialNum = (CertificateSerialNumber) val;
+ }
+
+ /**
+ * Set the algorithm id of the certificate.
+ *
+ * @param val the Object class value for the AlgorithmId
+ * @exception CertificateException on invalid data.
+ */
+ private void setAlgorithmId(Object val) throws CertificateException {
+ if (!(val instanceof CertificateAlgorithmId)) {
+ throw new CertificateException(
+ "AlgorithmId class type invalid.");
+ }
+ algId = (CertificateAlgorithmId) val;
+ }
+
+ /**
+ * Set the issuer name of the certificate.
+ *
+ * @param val the Object class value for the issuer
+ * @exception CertificateException on invalid data.
+ */
+ private void setIssuer(Object val) throws CertificateException {
+ if (!(val instanceof CertificateIssuerName)) {
+ throw new CertificateException(
+ "Issuer class type invalid.");
+ }
+ issuer = (CertificateIssuerName) val;
+ }
+
+ /**
+ * Set the validity interval of the certificate.
+ *
+ * @param val the Object class value for the CertificateValidity
+ * @exception CertificateException on invalid data.
+ */
+ private void setValidity(Object val) throws CertificateException {
+ if (!(val instanceof CertificateValidity)) {
+ throw new CertificateException(
+ "CertificateValidity class type invalid.");
+ }
+ interval = (CertificateValidity) val;
+ }
+
+ /**
+ * Set the subject name of the certificate.
+ *
+ * @param val the Object class value for the Subject
+ * @exception CertificateException on invalid data.
+ */
+ private void setSubject(Object val) throws CertificateException {
+ if (!(val instanceof CertificateSubjectName)) {
+ throw new CertificateException(
+ "Subject class type invalid.");
+ }
+ subject = (CertificateSubjectName) val;
+ }
+
+ /**
+ * Set the public key in the certificate.
+ *
+ * @param val the Object class value for the PublicKey
+ * @exception CertificateException on invalid data.
+ */
+ private void setKey(Object val) throws CertificateException {
+ if (!(val instanceof CertificateX509Key)) {
+ throw new CertificateException(
+ "Key class type invalid.");
+ }
+ pubKey = (CertificateX509Key) val;
+ }
+
+ /**
+ * Set the Issuer Unique Identity in the certificate.
+ *
+ * @param val the Object class value for the IssuerUniqueId
+ * @exception CertificateException
+ */
+ private void setIssuerUniqueId(Object val) throws CertificateException {
+ if (version.compare(CertificateVersion.V2) < 0) {
+ throw new CertificateException("Invalid version");
+ }
+ if (!(val instanceof CertificateIssuerUniqueIdentity)) {
+ throw new CertificateException(
+ "IssuerUniqueId class type invalid.");
+ }
+ issuerUniqueId = (CertificateIssuerUniqueIdentity) val;
+ }
+
+ /**
+ * Set the Subject Unique Identity in the certificate.
+ *
+ * @param val the Object class value for the SubjectUniqueId
+ * @exception CertificateException
+ */
+ private void setSubjectUniqueId(Object val) throws CertificateException {
+ if (version.compare(CertificateVersion.V2) < 0) {
+ throw new CertificateException("Invalid version");
+ }
+ if (!(val instanceof CertificateSubjectUniqueIdentity)) {
+ throw new CertificateException(
+ "SubjectUniqueId class type invalid.");
+ }
+ subjectUniqueId = (CertificateSubjectUniqueIdentity) val;
+ }
+
+ /**
+ * Set the extensions in the certificate.
+ *
+ * @param val the Object class value for the Extensions
+ * @exception CertificateException
+ */
+ private void setExtensions(Object val) throws CertificateException {
+ if (version.compare(CertificateVersion.V3) < 0) {
+ throw new CertificateException("Invalid version");
+ }
+ if (!(val instanceof CertificateExtensions)) {
+ throw new CertificateException(
+ "Extensions class type invalid.");
+ }
+ extensions = (CertificateExtensions) val;
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509ExtensionException.java b/base/util/src/netscape/security/x509/X509ExtensionException.java
new file mode 100644
index 000000000..c7174aed8
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509ExtensionException.java
@@ -0,0 +1,54 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * X.509 Extension Exception.
+ *
+ * @author Hemma Prafullchandra
+ * 1.2
+ */
+public class X509ExtensionException extends GeneralSecurityException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8152491877676477910L;
+
+ /**
+ * Constructs an X509ExtensionException with no detail message. A
+ * detail message is a String that describes this particular
+ * exception.
+ */
+ public X509ExtensionException() {
+ super();
+ }
+
+ /**
+ * Constructs the exception with the specified detail
+ * message. A detail message is a String that describes this
+ * particular exception.
+ *
+ * @param message the detail message.
+ */
+ public X509ExtensionException(String message) {
+ super(message);
+ }
+}
diff --git a/base/util/src/netscape/security/x509/X509Key.java b/base/util/src/netscape/security/x509/X509Key.java
new file mode 100644
index 000000000..a8253c0d8
--- /dev/null
+++ b/base/util/src/netscape/security/x509/X509Key.java
@@ -0,0 +1,508 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * Holds an X.509 key, for example a public key found in an X.509
+ * certificate. Includes a description of the algorithm to be used
+ * with the key; these keys normally are used as
+ * "SubjectPublicKeyInfo".
+ *
+ * <P>
+ * While this class can represent any kind of X.509 key, it may be desirable to provide subclasses which understand how
+ * to parse keying data. For example, RSA public keys have two members, one for the public modulus and one for the prime
+ * exponent. If such a class is provided, it is used when parsing X.509 keys. If one is not provided, the key still
+ * parses correctly.
+ *
+ * @version 1.74, 97/12/10
+ * @author David Brownell
+ */
+public class X509Key implements PublicKey {
+
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = -5359250853002055002L;
+
+ /* The algorithm information (name, parameters, etc). */
+ protected AlgorithmId algid;
+
+ /* The key bytes, without the algorithm information */
+ protected byte[] key;
+
+ /* The encoding for the key. */
+ protected byte[] encodedKey;
+
+ /**
+ * Default constructor. The key constructed must have its key
+ * and algorithm initialized before it may be used, for example
+ * by using <code>decode</code>.
+ */
+ public X509Key() {
+ }
+
+ /*
+ * Build and initialize as a "default" key. All X.509 key
+ * data is stored and transmitted losslessly, but no knowledge
+ * about this particular algorithm is available.
+ */
+ public X509Key(AlgorithmId algid, byte[] key)
+ throws InvalidKeyException {
+ this.algid = algid;
+ this.key = key;
+ encode();
+ }
+
+ /**
+ * Construct X.509 subject public key from a DER value. If
+ * the runtime environment is configured with a specific class for
+ * this kind of key, a subclass is returned. Otherwise, a generic
+ * X509Key object is returned.
+ *
+ * <P>
+ * This mechanism gurantees that keys (and algorithms) may be freely manipulated and transferred, without risk of
+ * losing information. Also, when a key (or algorithm) needs some special handling, that specific need can be
+ * accomodated.
+ *
+ * @param in the DER-encoded SubjectPublicKeyInfo value
+ * @exception IOException on data format errors
+ */
+ public static X509Key parse(DerValue in) throws IOException {
+ AlgorithmId algorithm;
+ X509Key subjectKey;
+
+ if (in.tag != DerValue.tag_Sequence)
+ throw new IOException("corrupt subject key");
+
+ algorithm = AlgorithmId.parse(in.data.getDerValue());
+ try {
+ subjectKey = buildX509Key(algorithm, in.data.getBitString());
+
+ } catch (InvalidKeyException e) {
+ throw new IOException("subject key, " + e.getMessage());
+ }
+
+ if (in.data.available() != 0)
+ throw new IOException("excess subject key");
+ return subjectKey;
+ }
+
+ /**
+ * Parse the key bits. This may be redefined by subclasses to take
+ * advantage of structure within the key. For example, RSA public
+ * keys encapsulate two unsigned integers (modulus and exponent) as
+ * DER values within the <code>key</code> bits; Diffie-Hellman and
+ * DSS/DSA keys encapsulate a single unsigned integer.
+ *
+ * <P>
+ * This function is called when creating X.509 SubjectPublicKeyInfo values using the X509Key member functions, such
+ * as <code>parse</code> and <code>decode</code>.
+ *
+ * @exception IOException on parsing errors.
+ * @exception InvalidKeyException on invalid key encodings.
+ */
+ protected void parseKeyBits() throws IOException, InvalidKeyException {
+ encode();
+ }
+
+ /*
+ * Factory interface, building the kind of key associated with this
+ * specific algorithm ID or else returning this generic base class.
+ * See the description above.
+ */
+ static X509Key buildX509Key(AlgorithmId algid, byte[] key)
+ throws IOException, InvalidKeyException {
+ /*
+ * Use the algid and key parameters to produce the ASN.1 encoding
+ * of the key, which will then be used as the input to the
+ * key factory.
+ */
+ DerOutputStream x509EncodedKeyStream = new DerOutputStream();
+ encode(x509EncodedKeyStream, algid, key);
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray());
+
+ try {
+ // Instantiate the key factory of the appropriate algorithm
+ KeyFactory keyFac = null;
+ if (Security.getProvider("Mozilla-JSS") == null) {
+ keyFac = KeyFactory.getInstance(algid.getName());
+ } else {
+ keyFac = KeyFactory.getInstance(algid.getName(),
+ "Mozilla-JSS");
+ }
+
+ // Generate the public key
+ PublicKey pubKey = keyFac.generatePublic(x509KeySpec);
+
+ if (pubKey instanceof X509Key) {
+ /*
+ * Return specialized X509Key, where the structure within the
+ * key has been parsed
+ */
+ return (X509Key) pubKey;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ // Return generic X509Key with opaque key data (see below)
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e.toString());
+ } catch (Exception e) {
+ throw new InvalidKeyException(e.toString());
+ }
+
+ /*
+ * Try again using JDK1.1-style for backwards compatibility.
+ */
+ String classname = "";
+ try {
+ Provider sunProvider;
+
+ sunProvider = Security.getProvider("SUN");
+ if (sunProvider == null)
+ throw new InstantiationException();
+ classname = sunProvider.getProperty("PublicKey.X.509." +
+ algid.getName());
+ if (classname == null) {
+ throw new InstantiationException();
+ }
+
+ Class<?> keyClass = Class.forName(classname);
+ Object inst;
+ X509Key result;
+
+ inst = keyClass.newInstance();
+ if (inst instanceof X509Key) {
+ result = (X509Key) inst;
+ result.algid = algid;
+ result.key = key;
+ result.parseKeyBits();
+ return result;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (InstantiationException e) {
+ } catch (IllegalAccessException e) {
+ // this should not happen.
+ throw new IOException(classname + " [internal error]");
+ }
+
+ X509Key result = new X509Key();
+ result.algid = algid;
+ result.key = key;
+ return result;
+ }
+
+ /**
+ * Returns the algorithm to be used with this key.
+ */
+ public String getAlgorithm() {
+ return algid.getName();
+ }
+
+ /**
+ * Returns the algorithm ID to be used with this key.
+ */
+ public AlgorithmId getAlgorithmId() {
+ return algid;
+ }
+
+ /**
+ * Encode SubjectPublicKeyInfo sequence on the DER output stream.
+ *
+ * @exception IOException on encoding errors.
+ */
+ public final void encode(DerOutputStream out) throws IOException {
+ encode(out, this.algid, this.key);
+ }
+
+ /**
+ * Returns the DER-encoded form of the key as a byte array.
+ */
+ public synchronized byte[] getEncoded() {
+ byte[] result = null;
+ try {
+ result = encode();
+ } catch (InvalidKeyException e) {
+ }
+ return result;
+ }
+
+ /**
+ * Returns the format for this key: "X.509"
+ */
+ public String getFormat() {
+ return "X.509";
+ }
+
+ /**
+ * Returns the raw key as a byte array
+ */
+ public byte[] getKey() {
+ return key;
+ }
+
+ /**
+ * Returns the DER-encoded form of the key as a byte array.
+ *
+ * @exception InvalidKeyException on encoding errors.
+ */
+ public byte[] encode() throws InvalidKeyException {
+ if (encodedKey == null) {
+ try {
+ DerOutputStream out;
+
+ out = new DerOutputStream();
+ encode(out);
+ encodedKey = out.toByteArray();
+
+ } catch (IOException e) {
+ throw new InvalidKeyException("IOException : " +
+ e.getMessage());
+ }
+ }
+ return copyEncodedKey(encodedKey);
+ }
+
+ /*
+ * Returns a printable representation of the key
+ */
+ public String toString() {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String keybits = pp.toHexString(key);
+
+ return "algorithm = " + algid.toString()
+ + ", unparsed keybits = \n" + keybits;
+ }
+
+ /**
+ * Initialize an X509Key object from an input stream. The data on that
+ * input stream must be encoded using DER, obeying the X.509 <code>SubjectPublicKeyInfo</code> format. That is, the
+ * data is a
+ * sequence consisting of an algorithm ID and a bit string which holds
+ * the key. (That bit string is often used to encapsulate another DER
+ * encoded sequence.)
+ *
+ * <P>
+ * Subclasses should not normally redefine this method; they should instead provide a <code>parseKeyBits</code>
+ * method to parse any fields inside the <code>key</code> member.
+ *
+ * <P>
+ * The exception to this rule is that since private keys need not be encoded using the X.509
+ * <code>SubjectPublicKeyInfo</code> format, private keys may override this method, <code>encode</code>, and of
+ * course <code>getFormat</code>.
+ *
+ * @param in an input stream with a DER-encoded X.509
+ * SubjectPublicKeyInfo value
+ * @exception InvalidKeyException on parsing errors.
+ */
+ public void decode(InputStream in)
+ throws InvalidKeyException {
+ DerValue val;
+
+ try {
+ val = new DerValue(in);
+ if (val.tag != DerValue.tag_Sequence)
+ throw new InvalidKeyException("invalid key format");
+
+ algid = AlgorithmId.parse(val.data.getDerValue());
+ key = val.data.getBitString();
+ parseKeyBits();
+ if (val.data.available() != 0)
+ throw new InvalidKeyException("excess key data");
+
+ } catch (IOException e) {
+ // e.printStackTrace ();
+ throw new InvalidKeyException("IOException : " +
+ e.getMessage());
+ }
+ }
+
+ public void decode(byte[] encodedKey) throws InvalidKeyException {
+ decode(new ByteArrayInputStream(encodedKey));
+ }
+
+ /**
+ * Serialization write ... X.509 keys serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void
+ writeObject(java.io.ObjectOutputStream stream)
+ throws IOException {
+ stream.write(getEncoded());
+ }
+
+ /**
+ * Serialization read ... X.509 keys serialize as
+ * themselves, and they're parsed when they get read back.
+ */
+ private synchronized void
+ readObject(ObjectInputStream stream)
+ throws IOException {
+
+ try {
+ decode(stream);
+
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ throw new IOException("deserialized key is invalid: " +
+ e.getMessage());
+ }
+ }
+
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object instanceof Key) {
+ Key key = (Key) object;
+
+ byte[] b1;
+ if (encodedKey != null) {
+ b1 = encodedKey;
+ } else {
+ b1 = getEncoded();
+ }
+ byte[] b2 = key.getEncoded();
+
+ return java.security.MessageDigest.isEqual(b1, b2);
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculates a hash code value for the object. Objects
+ * which are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+ byte[] b1 = getEncoded();
+
+ for (int i = 1; i < b1.length; i++) {
+ retval += b1[i] * i;
+ }
+ return (retval);
+ }
+
+ /*
+ * Make a copy of the encoded key.
+ */
+ private byte[] copyEncodedKey(byte[] encodedKey) {
+ int len = encodedKey.length;
+ byte[] copy = new byte[len];
+ System.arraycopy(encodedKey, 0, copy, 0, len);
+ return copy;
+ }
+
+ /*
+ * Produce SubjectPublicKey encoding from algorithm id and key material.
+ */
+ static void encode(DerOutputStream out, AlgorithmId algid, byte[] key)
+ throws IOException {
+ DerOutputStream tmp = new DerOutputStream();
+ algid.encode(tmp);
+ tmp.putBitString(key);
+ out.write(DerValue.tag_Sequence, tmp);
+ }
+
+ /*
+ * parsePublicKey returns a PublicKey for use with package JSS from within netscape.security.*.
+ * This function provide an interim solution for migrating from using the netscape.security.* package
+ * to using the JSS package.
+ */
+
+ public static PublicKey parsePublicKey(DerValue in) throws IOException {
+ AlgorithmId algorithm;
+ PublicKey subjectKey;
+
+ if (in.tag != DerValue.tag_Sequence)
+ throw new IOException("corrupt subject key");
+
+ algorithm = AlgorithmId.parse(in.data.getDerValue());
+ try {
+ subjectKey = buildPublicKey(algorithm, in.data.getBitString());
+
+ } catch (InvalidKeyException e) {
+ throw new IOException("subject key, " + e.getMessage());
+ }
+
+ if (in.data.available() != 0)
+ throw new IOException("excess subject key");
+ return subjectKey;
+ }
+
+ /* buildPublicKey returns a PublicKey for use with the JSS package from within netscape.security.*.
+ * This function provide an interim solution for migrating from using the netscape.security.* package
+ * to using the JSS package.
+ */
+ static PublicKey buildPublicKey(AlgorithmId algid, byte[] key)
+ throws IOException, InvalidKeyException {
+ /*
+ * Use the algid and key parameters to produce the ASN.1 encoding
+ * of the key, which will then be used as the input to the
+ * key factory.
+ */
+ DerOutputStream x509EncodedKeyStream = new DerOutputStream();
+ encode(x509EncodedKeyStream, algid, key);
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray());
+
+ try {
+ // Instantiate the key factory of the appropriate algorithm
+ KeyFactory keyFac = null;
+ if (Security.getProvider("Mozilla-JSS") == null) {
+ keyFac = KeyFactory.getInstance(algid.getName());
+ } else {
+ keyFac = KeyFactory.getInstance(algid.getName(),
+ "Mozilla-JSS");
+ }
+
+ // Generate the public key
+ PublicKey pubKey = keyFac.generatePublic(x509KeySpec);
+
+ /*
+ * Return specialized X509Key, where the structure within the
+ * key has been parsed
+ */
+ return pubKey;
+ } catch (NoSuchAlgorithmException e) {
+ // Return generic X509Key with opaque key data (see below)
+ throw new InvalidKeyException(e.toString());
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e.toString());
+ } catch (Exception e) {
+ throw new InvalidKeyException(e.toString());
+ }
+
+ }
+
+}
diff --git a/base/util/test/CMakeLists.txt b/base/util/test/CMakeLists.txt
new file mode 100644
index 000000000..592f3dbbb
--- /dev/null
+++ b/base/util/test/CMakeLists.txt
@@ -0,0 +1,60 @@
+project(pki-util-test Java)
+
+# TODO: create CMake function to find all Java files
+set(pki-util-test_SRCS
+ com/netscape/security/util/BMPStringTest.java
+ com/netscape/security/util/IA5StringTest.java
+ com/netscape/security/util/JSSUtil.java
+ com/netscape/security/util/PrintableStringTest.java
+ com/netscape/security/util/StringTestUtil.java
+ com/netscape/security/util/TeletexStringTest.java
+ com/netscape/security/util/UniversalStringTest.java
+ com/netscape/security/util/UTF8StringTest.java
+ com/netscape/security/x509/ConverterTestUtil.java
+ com/netscape/security/x509/DirStrConverterTest.java
+ com/netscape/security/x509/GenericValueConverterTest.java
+ com/netscape/security/x509/IA5StringConverterTest.java
+ com/netscape/security/x509/PrintableConverterTest.java
+)
+
+set(CMAKE_JAVA_INCLUDE_PATH
+ ${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR}
+ ${JSS_JAR} ${LDAPJDK_JAR} ${COMMONS_CODEC_JAR} ${XALAN_JAR} ${XERCES_JAR}
+ ${PKI_TEST_JAR} ${JUNIT_JAR}
+)
+
+set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})
+
+# build test jar file
+# TODO: create CMake function to compile without building jar file
+# TODO: build test only when the test is invoked
+set(CMAKE_JAR_CLASSES_PREFIX com/netscape)
+add_jar(pki-util-test ${pki-util-test_SRCS})
+add_dependencies(pki-util-test pki-nsutil pki-cmsutil pki-test)
+
+# create test target
+# do not include xalan and xerces in class path
+# TODO: create CMake function to find all JUnit test classes
+add_junit_test(test-pki-util
+ CLASSPATH
+ ${pki-util-test_JAR_FILE}
+ ${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR}
+ ${JSS_JAR} ${LDAPJDK_JAR} ${COMMONS_CODEC_JAR}
+ ${PKI_TEST_JAR} ${JUNIT_JAR}
+ TESTS
+ com.netscape.security.util.BMPStringTest
+ com.netscape.security.util.IA5StringTest
+ com.netscape.security.util.PrintableStringTest
+ com.netscape.security.util.TeletexStringTest
+ com.netscape.security.util.UniversalStringTest
+ com.netscape.security.util.UTF8StringTest
+ com.netscape.security.x509.DirStrConverterTest
+ com.netscape.security.x509.GenericValueConverterTest
+ com.netscape.security.x509.IA5StringConverterTest
+ com.netscape.security.x509.PrintableConverterTest
+ REPORTS_DIR
+ reports
+)
+
+# include test into the main test
+add_dependencies(test test-pki-util)
diff --git a/base/util/test/com/netscape/security/extensions/GenericASN1ExtensionTest.java b/base/util/test/com/netscape/security/extensions/GenericASN1ExtensionTest.java
new file mode 100644
index 000000000..74d082f09
--- /dev/null
+++ b/base/util/test/com/netscape/security/extensions/GenericASN1ExtensionTest.java
@@ -0,0 +1,72 @@
+package com.netscape.security.extensions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.Hashtable;
+
+import netscape.security.extensions.GenericASN1Extension;
+import netscape.security.x509.OIDMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GenericASN1ExtensionTest {
+
+ //@Test
+ public void testConstructorArgs() throws Exception {
+ String name1 = "testExtension1";
+ String oid1 = "1.2.3.4";
+ String pattern = "";
+ Hashtable<String, String> config = new Hashtable<String, String>();
+ GenericASN1Extension extension1 = new GenericASN1Extension(name1, oid1,
+ pattern, false, config);
+ Assert.assertEquals(name1, extension1.getName());
+ Assert.assertNotNull(OIDMap.getClass(name1));
+
+ String name2 = "testExtension2";
+ String oid2 = "2.4.6.8";
+ GenericASN1Extension extension2 = new GenericASN1Extension(name2, oid2,
+ pattern, false, config);
+ Assert.assertEquals(name2, extension2.getName());
+ Assert.assertNotNull(OIDMap.getClass(name2));
+ }
+
+ @Test
+ public void testConstructorJustConfig() throws Exception {
+ String name1 = "testExtension1";
+ String oid1 = "1.2.3.4";
+ String pattern = "";
+ Hashtable<String, String> config = new Hashtable<String, String>();
+ config.put("oid", oid1);
+ config.put("name", name1);
+ config.put("pattern", pattern);
+ config.put("critical", "true");
+
+ GenericASN1Extension extension1 = new GenericASN1Extension(config);
+ Assert.assertEquals(name1, extension1.getName());
+ //Assert.assertNotNull(OIDMap.getClass(name1));
+
+ String name2 = "testExtension2";
+ String oid2 = "2.4.6.8";
+ config.put("oid", oid2);
+ config.put("name", name2);
+
+ GenericASN1Extension extension2 = new GenericASN1Extension(config);
+ Assert.assertEquals(name2, extension2.getName());
+ //Assert.assertNotNull(OIDMap.getClass(name2));
+ OutputStream outputStream = new ByteArrayOutputStream();
+ extension1.encode(outputStream);
+ extension2.encode(outputStream);
+
+ }
+
+ @Test
+ public void testConstructorDER() throws Exception {
+ byte[] value = new byte[0];
+ GenericASN1Extension extension = new GenericASN1Extension(true, value);
+
+ OutputStream outputStream = new ByteArrayOutputStream();
+ extension.encode(outputStream);
+
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/BMPStringTest.java b/base/util/test/com/netscape/security/util/BMPStringTest.java
new file mode 100644
index 000000000..ffe13b238
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/BMPStringTest.java
@@ -0,0 +1,274 @@
+package com.netscape.security.util;
+
+import netscape.security.util.DerValue;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+public class BMPStringTest {
+
+ public byte tag = DerValue.tag_BMPString;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ String input = StringTestUtil.NULL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/IA5StringTest.java b/base/util/test/com/netscape/security/util/IA5StringTest.java
new file mode 100644
index 000000000..dd0af242c
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/IA5StringTest.java
@@ -0,0 +1,273 @@
+package com.netscape.security.util;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import sun.security.util.DerValue;
+
+public class IA5StringTest {
+
+ public byte tag = DerValue.tag_IA5String;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ String input = StringTestUtil.NULL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(DerValue.tag_UTF8String, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/JSSUtil.java b/base/util/test/com/netscape/security/util/JSSUtil.java
new file mode 100644
index 000000000..bbbabbf14
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/JSSUtil.java
@@ -0,0 +1,73 @@
+package com.netscape.security.util;
+
+import netscape.security.util.DerValue;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BMPString;
+import org.mozilla.jss.asn1.IA5String;
+import org.mozilla.jss.asn1.PrintableString;
+import org.mozilla.jss.asn1.Tag;
+import org.mozilla.jss.asn1.TeletexString;
+import org.mozilla.jss.asn1.UTF8String;
+import org.mozilla.jss.asn1.UniversalString;
+
+public class JSSUtil {
+
+ public static byte[] encode(byte tag, String string) throws Exception {
+ ASN1Value value;
+
+ switch (tag) {
+ case DerValue.tag_BMPString:
+ value = new BMPString(string);
+ break;
+ case DerValue.tag_IA5String:
+ value = new IA5String(string);
+ break;
+ case DerValue.tag_PrintableString:
+ value = new PrintableString(string);
+ break;
+ case DerValue.tag_T61String:
+ value = new TeletexString(string);
+ break;
+ case DerValue.tag_UniversalString:
+ value = new UniversalString(string);
+ break;
+ case DerValue.tag_UTF8String:
+ value = new UTF8String(string);
+ break;
+ default:
+ throw new Exception("Unsupported tag: " + tag);
+ }
+ return ASN1Util.encode(value);
+ }
+
+ public static String decode(byte tag, byte[] bytes) throws Exception {
+ ASN1Template template;
+
+ switch (tag) {
+ case DerValue.tag_BMPString:
+ template = new BMPString.Template();
+ break;
+ case DerValue.tag_IA5String:
+ template = new IA5String.Template();
+ break;
+ case DerValue.tag_PrintableString:
+ template = new PrintableString.Template();
+ break;
+ case DerValue.tag_T61String:
+ template = new TeletexString.Template();
+ break;
+ case DerValue.tag_UniversalString:
+ template = new UniversalString.Template();
+ break;
+ case DerValue.tag_UTF8String:
+ template = new UTF8String.Template();
+ break;
+ default:
+ throw new Exception("Unsupported tag: " + tag);
+ }
+ return ASN1Util.decode(new Tag(Tag.UNIVERSAL, tag), template, bytes).toString();
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/PrintableStringTest.java b/base/util/test/com/netscape/security/util/PrintableStringTest.java
new file mode 100644
index 000000000..5808a2650
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/PrintableStringTest.java
@@ -0,0 +1,290 @@
+package com.netscape.security.util;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import sun.security.util.DerValue;
+
+public class PrintableStringTest {
+
+ public byte tag = DerValue.tag_PrintableString;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ byte[] data = { 0x13, 0x01, 0x00 };
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ String expected = ""; // skip null chars (bug 359010)
+ System.out.println(" - expected: [" + expected + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(expected, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(DerValue.tag_UTF8String, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(DerValue.tag_UTF8String, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, StringTestUtil.MULTIBYTE_CHARS);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(DerValue.tag_UTF8String, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/StringTestUtil.java b/base/util/test/com/netscape/security/util/StringTestUtil.java
new file mode 100644
index 000000000..16810581c
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/StringTestUtil.java
@@ -0,0 +1,79 @@
+package com.netscape.security.util;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+public class StringTestUtil {
+
+ public final static String NULL_CHARS = "\u0000";
+
+ public final static String PRINTABLE_CHARS =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \'()+,-./:=?";
+
+ public final static String NON_PRINTABLE_CHARS = "\"\\";
+
+ public final static String CONTROL_CHARS = "\b\t\n\f\r";
+
+ public final static String MULTIBYTE_CHARS = "我爱你"; // I love you
+
+ public static String toString(byte[] array) {
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0)
+ sb.append(" ");
+ sb.append(Integer.toHexString(0xff & array[i] | 0x100).substring(1).toUpperCase());
+ }
+
+ return sb.toString();
+ }
+
+ public static byte[] normalizeUnicode(byte[] data) throws Exception {
+
+ DerValue value = new DerValue(data);
+ byte[] tmp = value.data.toByteArray();
+
+ if (tmp[0] == -2 && tmp[1] == -1) { // remove optional big-endian byte-order mark
+
+ byte tag = value.tag;
+ int length = value.length() - 2;
+
+ DerOutputStream os = new DerOutputStream();
+ os.putTag((byte) 0, false, tag);
+ os.putLength(length);
+ os.write(tmp, 2, length);
+
+ return os.toByteArray();
+ }
+
+ return data;
+ }
+
+ public static byte[] encode(byte tag, String string) throws Exception {
+ DerOutputStream os = new DerOutputStream();
+ os.putStringType(tag, string);
+ return os.toByteArray();
+ }
+
+ public static String decode(byte tag, byte[] bytes) throws Exception {
+ DerInputStream is = new DerInputStream(bytes);
+
+ switch (tag) {
+ case DerValue.tag_BMPString:
+ return is.getBMPString();
+ case DerValue.tag_IA5String:
+ return is.getIA5String();
+ case DerValue.tag_PrintableString:
+ return is.getPrintableString();
+ case DerValue.tag_T61String:
+ return is.getT61String();
+ case DerValue.tag_UniversalString:
+ return is.getUniversalString();
+ case DerValue.tag_UTF8String:
+ return is.getDerValue().getUTF8String();
+ default:
+ throw new Exception("Unsupported tag: " + tag);
+ }
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/TeletexStringTest.java b/base/util/test/com/netscape/security/util/TeletexStringTest.java
new file mode 100644
index 000000000..69f46c220
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/TeletexStringTest.java
@@ -0,0 +1,273 @@
+package com.netscape.security.util;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import sun.security.util.DerValue;
+
+public class TeletexStringTest {
+
+ public byte tag = DerValue.tag_T61String;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ String input = StringTestUtil.NULL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(DerValue.tag_UTF8String, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: IOException");
+
+ try {
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IOException);
+ }
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/UTF8StringTest.java b/base/util/test/com/netscape/security/util/UTF8StringTest.java
new file mode 100644
index 000000000..6bffb28b6
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/UTF8StringTest.java
@@ -0,0 +1,262 @@
+package com.netscape.security.util;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import sun.security.util.DerValue;
+
+public class UTF8StringTest {
+
+ public byte tag = DerValue.tag_UTF8String;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, "");
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, "");
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ String input = StringTestUtil.NULL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/util/UniversalStringTest.java b/base/util/test/com/netscape/security/util/UniversalStringTest.java
new file mode 100644
index 000000000..5f09f1f8e
--- /dev/null
+++ b/base/util/test/com/netscape/security/util/UniversalStringTest.java
@@ -0,0 +1,262 @@
+package com.netscape.security.util;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import sun.security.util.DerValue;
+
+public class UniversalStringTest {
+
+ public byte tag = DerValue.tag_UniversalString;
+
+ @Test
+ public void testEncodingEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingEmptyString() throws Exception {
+
+ String input = "";
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNullCharacters() throws Exception {
+
+ String input = StringTestUtil.NULL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingNonPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.NON_PRINTABLE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingNonPrintableCharacters() throws Exception {
+
+ String input = StringTestUtil.NON_PRINTABLE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + input + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + output + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Encoding: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingControlCharacters() throws Exception {
+
+ String input = StringTestUtil.CONTROL_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Encoding: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(tag, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = StringTestUtil.encode(tag, string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testDecodingMultibyteCharacters() throws Exception {
+
+ String input = StringTestUtil.MULTIBYTE_CHARS;
+ byte[] data = JSSUtil.encode(tag, input);
+
+ System.out.println("Decoding: [" + StringTestUtil.toString(data) + "]");
+
+ System.out.println(" - expected: [" + StringTestUtil.toString(input.getBytes()) + "]");
+
+ String output = StringTestUtil.decode(tag, data);
+ System.out.println(" - actual : [" + StringTestUtil.toString(output.getBytes()) + "]");
+
+ Assert.assertEquals(input, output);
+ }
+
+ @Test
+ public void testEncodingTime() throws Exception {
+
+ System.out.println("Encoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.encode(tag, string);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.encode(tag, string);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+
+ @Test
+ public void testDecodingTime() throws Exception {
+
+ System.out.println("Decoding time:");
+
+ String string = StringTestUtil.NULL_CHARS +
+ StringTestUtil.PRINTABLE_CHARS +
+ StringTestUtil.NON_PRINTABLE_CHARS +
+ StringTestUtil.CONTROL_CHARS +
+ StringTestUtil.MULTIBYTE_CHARS;
+
+ byte[] data = JSSUtil.encode(tag, string);
+
+ long t0 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ JSSUtil.decode(tag, data);
+
+ long t1 = System.currentTimeMillis();
+
+ for (int i = 0; i < 10000; i++)
+ StringTestUtil.decode(tag, data);
+
+ long t2 = System.currentTimeMillis();
+
+ long time1 = t1 - t0;
+ long time2 = t2 - t1;
+
+ System.out.println(" - JSS : " + time1 + " ms");
+ System.out.println(" - Internal: " + time2 + " ms");
+ }
+}
diff --git a/base/util/test/com/netscape/security/x509/ConverterTestUtil.java b/base/util/test/com/netscape/security/x509/ConverterTestUtil.java
new file mode 100644
index 000000000..748c1b284
--- /dev/null
+++ b/base/util/test/com/netscape/security/x509/ConverterTestUtil.java
@@ -0,0 +1,22 @@
+package com.netscape.security.x509;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.AVAValueConverter;
+
+public class ConverterTestUtil {
+
+ public static byte[] convert(AVAValueConverter converter, String string, byte[] tags) throws Exception {
+
+ DerOutputStream os = new DerOutputStream();
+
+ DerValue value = converter.getValue(string, tags);
+ value.encode(os);
+
+ return os.toByteArray();
+ }
+
+ public static byte[] convert(AVAValueConverter converter, String string) throws Exception {
+ return convert(converter, string, null);
+ }
+}
diff --git a/base/util/test/com/netscape/security/x509/DirStrConverterTest.java b/base/util/test/com/netscape/security/x509/DirStrConverterTest.java
new file mode 100644
index 000000000..0549dec9c
--- /dev/null
+++ b/base/util/test/com/netscape/security/x509/DirStrConverterTest.java
@@ -0,0 +1,122 @@
+package com.netscape.security.x509;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import com.netscape.security.util.JSSUtil;
+import com.netscape.security.util.StringTestUtil;
+
+import netscape.security.util.DerValue;
+import netscape.security.x509.DirStrConverter;
+
+public class DirStrConverterTest {
+
+ @Test
+ public void testEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_T61String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_T61String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_UniversalString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testPrintableCharactersWithTags() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string, new byte[] {
+ DerValue.tag_IA5String, DerValue.tag_UTF8String
+ });
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMultibyteCharactersWithTags() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_UTF8String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new DirStrConverter(), string, new byte[] {
+ DerValue.tag_IA5String, DerValue.tag_UTF8String
+ });
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+}
diff --git a/base/util/test/com/netscape/security/x509/GenericValueConverterTest.java b/base/util/test/com/netscape/security/x509/GenericValueConverterTest.java
new file mode 100644
index 000000000..46ea86cc7
--- /dev/null
+++ b/base/util/test/com/netscape/security/x509/GenericValueConverterTest.java
@@ -0,0 +1,125 @@
+package com.netscape.security.x509;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import com.netscape.security.util.JSSUtil;
+import com.netscape.security.util.StringTestUtil;
+
+import netscape.security.util.DerValue;
+import netscape.security.x509.GenericValueConverter;
+
+public class GenericValueConverterTest {
+
+ @Test
+ public void testEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_BMPString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ actual = StringTestUtil.normalizeUnicode(actual);
+ System.out.println(" - norm. : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testPrintableCharactersWithTags() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_T61String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string, new byte[] {
+ DerValue.tag_T61String, DerValue.tag_UniversalString
+ });
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMultibyteCharactersWithTags() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_UniversalString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new GenericValueConverter(), string, new byte[] {
+ DerValue.tag_T61String, DerValue.tag_UniversalString
+ });
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+}
diff --git a/base/util/test/com/netscape/security/x509/IA5StringConverterTest.java b/base/util/test/com/netscape/security/x509/IA5StringConverterTest.java
new file mode 100644
index 000000000..ba99218ad
--- /dev/null
+++ b/base/util/test/com/netscape/security/x509/IA5StringConverterTest.java
@@ -0,0 +1,93 @@
+package com.netscape.security.x509;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import com.netscape.security.util.JSSUtil;
+import com.netscape.security.util.StringTestUtil;
+
+import netscape.security.util.DerValue;
+import netscape.security.x509.IA5StringConverter;
+
+public class IA5StringConverterTest {
+
+ @Test
+ public void testEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new IA5StringConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new IA5StringConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new IA5StringConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_IA5String, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new IA5StringConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ System.out.println(" - expected: IllegalArgumentException");
+
+ try {
+ byte[] actual = ConverterTestUtil.convert(new IA5StringConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+ }
+}
diff --git a/base/util/test/com/netscape/security/x509/PrintableConverterTest.java b/base/util/test/com/netscape/security/x509/PrintableConverterTest.java
new file mode 100644
index 000000000..a7acc9c90
--- /dev/null
+++ b/base/util/test/com/netscape/security/x509/PrintableConverterTest.java
@@ -0,0 +1,103 @@
+package com.netscape.security.x509;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import com.netscape.security.util.JSSUtil;
+import com.netscape.security.util.StringTestUtil;
+
+import netscape.security.util.DerValue;
+import netscape.security.x509.PrintableConverter;
+
+public class PrintableConverterTest {
+
+ @Test
+ public void testEmptyString() throws Exception {
+
+ String string = "";
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new PrintableConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testNullCharacters() throws Exception {
+
+ String string = StringTestUtil.NULL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ System.out.println(" - expected: IllegalArgumentException");
+
+ try {
+ byte[] actual = ConverterTestUtil.convert(new PrintableConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+ }
+
+ @Test
+ public void testPrintableCharacters() throws Exception {
+
+ String string = StringTestUtil.PRINTABLE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ byte[] expected = JSSUtil.encode(DerValue.tag_PrintableString, string);
+ System.out.println(" - expected: " + StringTestUtil.toString(expected));
+
+ byte[] actual = ConverterTestUtil.convert(new PrintableConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testControlCharacters() throws Exception {
+
+ String string = StringTestUtil.CONTROL_CHARS;
+ System.out.println("Converting: [" + StringTestUtil.toString(string.getBytes()) + "]");
+
+ System.out.println(" - expected: IllegalArgumentException");
+
+ try {
+ byte[] actual = ConverterTestUtil.convert(new PrintableConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+ }
+
+ @Test
+ public void testMultibyteCharacters() throws Exception {
+
+ String string = StringTestUtil.MULTIBYTE_CHARS;
+ System.out.println("Converting: [" + string + "]");
+
+ System.out.println(" - expected: IllegalArgumentException");
+
+ try {
+ byte[] actual = ConverterTestUtil.convert(new PrintableConverter(), string);
+ System.out.println(" - actual : " + StringTestUtil.toString(actual));
+
+ Assert.fail();
+
+ } catch (Exception e) {
+ System.out.println(" - actual : " + e.getClass().getSimpleName());
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+ }
+}