Security Developer Guide
Security Developer Guide
Release 11
E94828-34
March 2026
Java Platform, Standard Edition Security Developer’s Guide, Release 11
E94828-34
This software and related documentation are provided under a license agreement containing restrictions on use and
disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or
allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit,
perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation
of this software, unless required by law for interoperability, is prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If you find
any errors, please report them to us in writing.
If this is software, software documentation, data (as defined in the Federal Acquisition Regulation), or related
documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, then
the following notice is applicable:
U.S. GOVERNMENT END USERS: Oracle programs (including any operating system, integrated software, any
programs embedded, installed, or activated on delivered hardware, and modifications of such programs) and Oracle
computer documentation or other Oracle data delivered to or accessed by U.S. Government end users are "commercial
computer software," "commercial computer software documentation," or "limited rights data" pursuant to the applicable
Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, reproduction,
duplication, release, display, disclosure, modification, preparation of derivative works, and/or adaptation of i) Oracle
programs (including any operating system, integrated software, any programs embedded, installed, or activated on
delivered hardware, and modifications of such programs), ii) Oracle computer documentation and/or iii) other Oracle
data, is subject to the rights and limitations specified in the license contained in the applicable contract. The terms
governing the U.S. Government's use of Oracle cloud services are defined by the applicable contract for such services.
No other rights are granted to the U.S. Government.
This software or hardware is developed for general use in a variety of information management applications. It is not
developed or intended for use in any inherently dangerous applications, including applications that may create a risk of
personal injury. If you use this software or hardware in dangerous applications, then you shall be responsible to take all
appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle Corporation and its
affiliates disclaim any liability for any damages caused by use of this software or hardware in dangerous applications.
Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates. Other names may be
trademarks of their respective owners.
Intel and Intel Inside are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used
under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Epyc, and the AMD logo
are trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open
Group.
This software or hardware and documentation may provide access to or information about content, products, and
services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all
warranties of any kind with respect to third-party content, products, and services unless otherwise set forth in an
applicable agreement between you and Oracle. Oracle Corporation and its affiliates will not be responsible for any loss,
costs, or damages incurred due to your access to or use of third-party content, products, or services, except as set forth
in an applicable agreement between you and Oracle.
Contents
Preface
Audience i
Related Documents i
Conventions i
1 General Security
Terms and Definitions 1
Java Security Overview 4
Introduction to Java Security 4
Java Language Security and Bytecode Verification 5
Basic Security Architecture 6
Security Providers 6
File Locations 8
Java Cryptography 9
Public Key Infrastructure 10
Key and Certificate Storage 10
Public Key Infrastructure Tools 11
Authentication 12
Secure Communication 13
TLS and DTLS Protocols 13
Simple Authentication and Security Layer (SASL) 14
Generic Security Service API and Kerberos 14
Access Control 15
Permissions 15
Security Policy 16
Access Control Enforcement 16
Java API for XML Processing (JAXP) 19
XML Signature 19
Deprecated Security APIs Marked for Removal 19
Security Tools Summary 20
Built-In Providers 21
The Security Properties File 21
Specifying an Alternative Security Properties File 22
Audience
This document is intended for experienced developers who build applications using the
comprehensive Java security framework. It is also intended for the user or administrator with a
set of tools to securely manage applications.
Related Documents
• Serialization Filtering in Java Platform, Standard Edition Java Core Libraries Developer's
Guide
• RMI Security Recommendations in Java Platform, Standard Edition Java Remote Method
Invocation User's Guide
Conventions
The following text conventions are used in this document:
Convention Meaning
boldface Boldface type indicates graphical user interface elements associated with an
action, or terms defined in text or the glossary.
italic Italic type indicates book titles, emphasis, or placeholder variables for which
you supply particular values.
monospace Monospace type indicates commands within a paragraph, URLs, code in
examples, text that appears on the screen, or text that you enter.
Terms and Definitions list commonly used cryptography terms and their definitions.
Java Security Overview provides an overview of the motivation of major security features, an
introduction to security classes and their usage, a discussion of the impact of the security
architecture on code, and thoughts on writing security-sensitive code.
Java SE Platform Security Architecture gives an overview of the motivation of the major
security features implemented for the JDK.
Java Security Standard Algorithm Names Specification describes the set of standard names
for algorithms, certificate and keystore types that Java SE requires and uses.
Permissions in the JDK describes the built-in JDK permission types and discusses the risks of
granting each permission.
Troubleshooting Security lists options for the [Link] system property that
enable you to monitor security access.
authentication
The process of confirming the identity of a party with whom one is communicating.
certificate
A digitally signed statement vouching for the identity and public key of an entity (person,
company, and so on). Certificates can either be self-signed or issued by a Certificate Authority
(CA), an entity that is trusted to issue valid certificates for other entities. Well-known CAs
include Comodo, DigiCert, and GoDaddy. X.509 is a common certificate format that can be
managed by the JDK's keytool.
cipher suite
A combination of cryptographic parameters that define the security algorithms and key sizes
used for authentication, key agreement, encryption, and integrity protection.
decryption
See encryption/decryption.
digital signature
A digital equivalent of a handwritten signature. It is used to ensure that data transmitted over a
network was sent by whoever claims to have sent it and that the data has not been modified in
transit. For example, an RSA-based digital signature is calculated by first computing a
cryptographic hash of the data and then encrypting the hash with the sender's private key.
encryption/decryption
Encryption is the process of using a complex algorithm to convert an original message
(cleartext) to an encoded message (ciphertext) that is unintelligible unless it is decrypted.
Decryption is the inverse process of producing cleartext from ciphertext.
The algorithms used to encrypt and decrypt data typically come in two categories: secret key
(symmetric) cryptography and public key (asymmetric) cryptography.
endpoint identification
An IPv4 or IPv6 address used to identify an endpoint on the network.
Endpoint identification procedures are handled during SSL/TLS handshake.
handshake protocol
The negotiation phase during which the two socket peers agree to use a new or existing
session. The handshake protocol is a series of messages exchanged over the record protocol.
At the end of the handshake, new connection-specific encryption and integrity protection keys
are generated based on the key agreement secrets in the session.
java-home
Variable placeholder used throughout this document to refer to the directory where the Java
Development Kit (JDK) is installed.
key agreement
A method by which two parties cooperate to establish a common key. Each side generates
some data, which is exchanged. These two pieces of data are then combined to generate a
key. Only those holding the proper private initialization data can obtain the final key. Diffie-
Hellman (DH) is the most common example of a key agreement algorithm.
key exchange
A method by which keys are exchanged. One side generates a private key and encrypts it
using the peer's public key (typically RSA). The data is transmitted to the peer, who decrypts
the key using the corresponding private key.
keystore/truststore
A keystore is a database of key material. Key material is used for a variety of purposes,
including authentication and data integrity. Various types of keystores are available, including
PKCS12 and the macOS KeychainStore.
Generally speaking, keystore information can be grouped into two categories: key entries and
trusted certificate entries. A key entry consists of an entity's identity and its private key, and
can be used for a variety of cryptographic purposes. In contrast, a trusted certificate entry
contains only a public key in addition to the entity's identity. Thus, a trusted certificate entry
can’t be used where a private key is required, such as in a [Link]. In the
JDK implementation of PKCS12, a keystore may contain both key entries and trusted
certificate entries.
A truststore is a keystore that is used when making decisions about what to trust. If you
receive data from an entity that you already trust, and if you can verify that the entity is the one
that it claims to be, then you can assume that the data really came from that entity.
An entry should only be added to a truststore if the user trusts that entity. By either generating
a key pair or by importing a certificate, the user gives trust to that entry. Any entry in the
truststore is considered a trusted entry.
It may be useful to have two different keystore files: one containing just your key entries, and
the other containing your trusted certificate entries, including CA certificates. The former
contains private information, whereas the latter does not. Using two files instead of a single
keystore file provides a cleaner separation of the logical distinction between your own
certificates (and corresponding private keys) and others' certificates. To provide more
protection for your private keys, store them in a keystore with restricted access, and provide
the trusted certificates in a more publicly accessible keystore if needed.
public-key cryptography
A cryptographic system that uses an encryption algorithm in which two keys are produced.
One key is made public, whereas the other is kept private. The public key and the private key
are cryptographic inverses; what one key encrypts only the other key can decrypt. Public-key
cryptography is also called asymmetric cryptography.
Record Protocol
A protocol that packages all data (whether application-level or as part of the handshake
process) into discrete records of data much like a TCP stream socket converts an application
byte stream into network packets. The individual records are then protected by the current
encryption and integrity protection keys.
secret-key cryptography
A cryptographic system that uses an encryption algorithm in which the same key is used both
to encrypt and decrypt the data. Secret-key cryptography is also called symmetric
cryptography.
session
A named collection of state information including authenticated peer identity, cipher suite, and
key agreement secrets that are negotiated through a secure socket handshake and that can
be shared among multiple secure socket instances.
trust manager
See key manager/trust manager.
truststore
See keystore/truststore.
Module Description
[Link] Defines the foundational APIs of Java SE.
Contained packages include [Link],
[Link], [Link], and
[Link].
[Link] Defines the Java binding of the IETF Generic
Security Services API (GSS-API). This module also
contains GSS-API mechanisms including Kerberos
v5 and SPNEGO.
[Link] Defines Java support for the IETF Simple
Authentication and Security Layer (SASL). This
module also contains SASL mechanisms including
DIGEST-MD5, CRAM-MD5, and NTLM,
[Link] Defines the Java Smart Card I/O API.
[Link] Defines the API for XML cryptography.
[Link] Defines APIs for signing JAR files.
[Link] Provides implementations of the
[Link].* interfaces and
various authentication modules.
[Link] Defines Java extensions to the GSS-API and an
implementation of the SASL GSS-API mechanism.
Implementation independence
Applications do not need to implement security themselves. Rather, they can request security
services from the JDK. Security services are implemented in providers (see the section
Security Providers), which are plugged into the JDK via a standard interface. An application
may rely on multiple independent providers for security functionality.
Implementation interoperability
Providers are interoperable across applications. Specifically, an application is not bound to a
specific provider if it does not rely on default values from the provider.
Algorithm extensibility
The JDK includes a number of built-in providers that implement a basic set of security services
that are widely used today. However, some applications may rely on emerging standards not
yet implemented, or on proprietary services. The JDK supports the installation of custom
providers that implement such services.
Security Providers
The [Link] class encapsulates the notion of a security provider in the Java
platform. It specifies the provider's name and lists the security services it implements. Multiple
providers may be configured at the same time and are listed in order of preference. When a
security service is requested, the highest priority provider that implements that service is
selected.
Applications rely on the relevant getInstance method to request a security service from an
underlying provider.
For example, message digest creation represents one type of service available from providers.
To request an implementation of a specific message digest algorithm, call the method
[Link]. The following statement requests a
SHA-256 message digest implementation without specifying a provider name:
MessageDigest md = [Link]("SHA-256");
The following figure illustrates how this statement obtains a SHA-256 message digest
implementation. The providers are searched in preference order, and the implementation from
the first provider supplying that particular algorithm, ProviderB, is returned.
You can optionally request an implementation from a specific provider by specifying the
provider's name. The following statement requests a SHA-256 message digest implementation
from a specific provider, ProviderC:
The following figure illustrates how this statement requests a SHA-256 message digest
implementation from a specific provider, ProviderC. In this case, the implementation from that
provider is returned, even though a provider with a higher preference order, ProviderB, also
supplies a SHA-256 implementation.
Figure 1-2 Request SHA-256 Message Digest Implementation from Specific Provider
For more information about cryptographic services, such as message digest algorithms, see
the section Java Cryptography.
Oracle's implementation of the Java platform includes a number of built-in default providers
that implement a basic set of security services that can be used by applications. Note that
other vendor implementations of the Java platform may include different sets of providers that
encapsulate vendor-specific sets of security services. The term built-in default providers refers
to the providers available in Oracle's implementation.
File Locations
The following table lists locations of some security-related files and tools.
Java Cryptography
The Java cryptography architecture is a framework for accessing and developing cryptographic
functionality for the Java platform.
It includes APIs for a large variety of cryptographic services, including the following:
• Message digest algorithms
• Digital signature algorithms
• Symmetric bulk and stream encryption
• Asymmetric encryption
• Password-based encryption (PBE)
• Elliptic Curve Cryptography (ECC)
• Key agreement algorithms
• Key generators
• Message Authentication Codes (MACs)
• Secure Random Number Generators
For historical (export control) reasons, the cryptography APIs are organized into two distinct
packages:
• The [Link] and [Link].* packages contains classes that are not subject
to export controls (like Signature and MessageDigest)
• The [Link] package contains classes that are subject to export controls (like
Cipher and KeyAgreement)
The cryptographic interfaces are provider-based, allowing for multiple and interoperable
cryptography implementations. Some providers may perform cryptographic operations in
software; others may perform the operations on a hardware token (for example, on a smart
card device or on a hardware cryptographic accelerator). Providers that implement export-
controlled services must be digitally signed by a certificate issued by the Oracle JCE Certificate
Authority.
The Java platform includes built-in providers for many of the most commonly used
cryptographic algorithms, including the RSA, DSA, and ECDSA signature algorithms, the AES
encryption algorithm, the SHA-2 message digest algorithms, and the Diffie-Hellman (DH) and
Elliptic Curve Diffie-Hellman (ECDH) key agreement algorithms. Most of the built-in providers
implement cryptographic algorithms in Java code.
The Java platform also includes a built-in provider that acts as a bridge to a native PKCS#11
(v2.x) token. This provider, named SunPKCS11, allows Java applications to seamlessly access
cryptographic services located on PKCS#11-compliant tokens.
On Windows, the Java platform includes a built-in provider that acts as a bridge to the native
Microsoft CryptoAPI. This provider, named SunMSCAPI, allows Java applications to seamlessly
access cryptographic services on Windows through the CryptoAPI.
The SunPKCS11 provider mentioned in the section Java Cryptography includes a PKCS11
KeyStore implementation. This means that keys and certificates residing in secure hardware
(such as a smart card) can be accessed and used by Java applications via the KeyStore API.
Note that smart card keys may not be permitted to leave the device. In such cases, the
[Link] object returned by the KeyStore API may simply be a reference to the key
(that is, it would not contain the actual key material). Such a Key object can only be used to
perform cryptographic operations on the device where the actual key resides.
The Java platform also includes an LDAP certificate store type (for accessing certificates
stored in an LDAP directory), as well as an in-memory Collection certificate store type (for
accessing certificates managed in a [Link] object).
The Java platform supports native Microsoft Windows keystore types. See the algorithm
names for the KeyStore engine class in The SunMSCAPI Provider. The Java platform also
includes a KeyStore implementation that proivdes access to the macOS Keychain. See the
algorithm names for the KeyStore engine class in The Apple Provider.
Note
jarsigner can optionally generate signatures that include a timestamp. Systems
that verify JAR file signatures can check the timestamp and accept a JAR file that
was signed while the signing certificate was valid rather than requiring the
certificate to be current. (Certificates typically expire annually, and it is not
reasonable to expect JAR file creators to re-sign deployed JAR files annually.)
See keytool and jarsigner in Java Platform, Standard Edition Tools Reference.
Authentication
Authentication is the process of determining the identity of a user. In the context of the Java
runtime environment, it is the process of identifying the user of an executing Java program. In
certain cases, this process may rely on the services described in the section Java
Cryptography.
The Java platform provides APIs that enable an application to perform user authentication via
pluggable login modules. Applications call into the LoginContext class (in the
[Link] package), which in turn references a configuration. The
configuration specifies which login module (an implementation of the
[Link] interface) is to be used to perform the actual
authentication.
Since applications solely talk to the standard LoginContext API, they can remain independent
from the underlying plug-in modules. New or updated modules can be plugged in for an
application without having to modify the application itself. The following figure illustrates the
independence between applications and underlying login modules:
Figure 1-3 Authentication Login Modules Plugging into the Authentication Framework
It is important to note that although login modules are pluggable components that can be
configured into the Java platform, they are not plugged in via security providers. Therefore,
they do not follow the provider searching model as described in the section Security Providers.
Instead, as is shown in Figure 1-3, login modules are administered by their own unique
configuration.
The Java platform provides the following built-in login modules, all in the
[Link] package:
Secure Communication
The data that travels across a network can be accessed by someone who is not the intended
recipient. When the data includes private information, such as passwords and credit card
numbers, steps must be taken to make the data unintelligible to unauthorized parties. It is also
important to ensure that you are sending the data to the appropriate party, and that the data
has not been modified, either intentionally or unintentionally, during transport.
Cryptography forms the basis required for secure communication; see the section Java
Cryptography. The Java platform also provides API support and provider implementations for a
number of standard secure communication protocols.
The JDK also includes APIs that support the notion of pluggable (provider-based) key
managers and trust managers. A key manager is encapsulated by the
[Link] class, and manages the keys used to perform authentication. A
trust manager is encapsulated by the TrustManager class (in the same package), and makes
decisions about who to trust based on certificates in the key store it manages.
The JDK includes a built-in provider that implements the SSL/TLS/DTLS protocols:
• SSL 3.0
• TLS 1.0
• TLS 1.1
• TLS 1.2
• TLS 1.3
• DTLS 1.0
• DTLS 1.2
SASL mechanism implementations are supplied in provider packages. Each provider may
support one or more SASL mechanisms and is registered and invoked via the standard
provider architecture.
The Java platform includes a built-in provider that implements the following SASL
mechanisms:
• CRAM-MD5, DIGEST-MD5, EXTERNAL, GSSAPI, NTLM, and PLAIN client mechanisms
• CRAM-MD5, DIGEST-MD5, GSSAPI, and NTLM server mechanisms
Note
The Krb5LoginModule mentioned in the section Authentication can be used in
conjunction with the GSS Kerberos mechanism.
The Java platform also includes a built-in implementation of the Simple and Protected GSS-
API Negotiation Mechanism (SPNEGO) GSS-API mechanism.
Before two applications can use GSS-API to securely exchange messages between them, they
must establish a joint security context. The context encapsulates shared state information that
might include, for example, cryptographic keys. Both applications create and use an
[Link] object to establish and maintain the shared information that
makes up the security context. Once a security context has been established, it can be used to
prepare secure messages for exchange.
The Java GSS APIs are in the [Link] package. The Java platform also defines basic
Kerberos classes, like KerberosPrincipal, KerberosTicket, KerberosKey, and KeyTab, which
are located in the [Link] package.
Access Control
The access control architecture in the Java platform protects access to sensitive resources (for
example, local files) or sensitive application code (for example, methods in a class). All access
control decisions are mediated by a security manager, represented by the
[Link] class. A SecurityManager must be installed into the Java runtime
in order to activate the access control checks.
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
Local applications executed via the java command are by default not run with a
SecurityManager installed. In order to run local applications with a SecurityManager, either the
application itself must programmatically set one via the setSecurityManager method (in the
[Link] class), or java must be invoked with a -[Link] argument
on the command line.
Permissions
A permission represents access to a system resource. In order for a resource access to be
allowed for an applet (or an application running with a security manager), the corresponding
permission must be explicitly granted to the code attempting the access.
When Java code is loaded by a class loader into the Java runtime, the class loader
automatically associates the following information with that code:
• Where the code was loaded from
• Who signed the code (if anyone)
• Default permissions granted to the code
This information is associated with the code regardless of whether the code is downloaded
over an untrusted network (e.g., an applet) or loaded from the filesystem (e.g., a local
application). The location from which the code was loaded is represented by a URL, the code
signer is represented by the signer's certificate chain, and default permissions are represented
by [Link] objects.
The default permissions automatically granted to downloaded code include the ability to make
network connections back to the host from which it originated. The default permissions
automatically granted to code loaded from the local filesystem include the ability to read files
from the directory it came from, and also from subdirectories of that directory.
Note that the identity of the user executing the code is not available at class loading time. It is
the responsibility of application code to authenticate the end user if necessary (see the section
Authentication). Once the user has been authenticated, the application can dynamically
associate that user with executing code by invoking the doAs method in the
[Link] class.
Security Policy
A limited set of default permissions are granted to code by class loaders. Administrators have
the ability to flexibly manage additional code permissions via a security policy.
Java SE encapsulates the notion of a security policy in the [Link] class.
There is only one Policy object installed into the Java runtime at any given time. The basic
responsibility of the Policy object is to determine whether access to a protected resource is
permitted to code (characterized by where it was loaded from, who signed it, and who is
executing it). How a Policy object makes this determination is implementation-dependent. For
example, it may consult a database containing authorization data, or it may contact another
service.
Java SE includes a default Policy implementation that reads its authorization data from one or
more ASCII (UTF-8) files configured in the security properties file. These policy files contain
the exact sets of permissions granted to code: specifically, the exact sets of permissions
granted to code loaded from particular locations, signed by particular entities, and executing as
particular users. The policy entries in each file must conform to a documented proprietary
syntax and may be composed via a simple text editor.
SecurityManager sm = [Link]();
if (sm != null) {
[Link](perm);
}
The Permission object perm corresponds to the requested access. For example, if an
attempt is made to read the file /tmp/abc, the permission may be constructed as follows:
Figure 1-4 illustrates access control enforcement. In this particular example, there are initially
two elements on the call stack, ClassA and ClassB. ClassA invokes a method in ClassB, which
In this example, ClassA and ClassB have different code characteristics – they come from
different locations and have different signers. Each may have been granted a different set of
permissions. The AccessController only grants access to the requested file if the Policy
indicates that both classes have been granted the required FilePermission.
Note
Secure Coding Guidelines for Java SE contains additional recommendations that can
help defend against XML-related attacks.
XML Signature
The Java XML Digital Signature API is a standard Java API for generating and validating XML
Signatures.
XML Signatures can be applied to data of any type, XML or binary (see XML Signature Syntax
and Processing). The resulting signature is represented in XML. An XML Signature can be
used to secure your data and provide data integrity, message authentication, and signer
authentication.
The API is designed to support all of the required or recommended features of the W3C
Recommendation for XML-Signature Syntax and Processing. The API is extensible and
pluggable and is based on the Java Cryptography Service Provider Architecture.
The Java XML Digital Signature API, which is in the [Link] module, consists of
six packages:
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link].X500Principal
• [Link]
• [Link]
The following methods are deprecated and marked for removal:
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
The following field is deprecated and marked for removal:
• [Link]
Tool Usage
jar Creates Java Archive (JAR) files
jarsigner Signs and verifies signatures on JAR files
keytool Creates and manages key stores
There are also three Kerberos-related tools that are shipped with the JDK for Windows.
Equivalent functionality is provided in tools of the same name that are automatically part of the
Solaris and Linux operating environments.
Tool Usage
kinit Obtains and caches Kerberos ticket-granting tickets
klist Lists entries in the local Kerberos credentials cache
and key table
ktab Manages the names and service keys stored in the
local Kerberos key table
Built-In Providers
The Java SE implementation from Oracle includes a number of built-in provider packages. See
JDK Providers Documentation.
propertyName=propertyValue
For example, suppose that you want to specify a different key manager factory algorithm name
than the default SunX509. You do this by specifying the algorithm name as the value of a
security property named [Link]. For example, to set the value to
MyX509, add the following line:
[Link]=MyX509
To comment out a line in a security properties file, which means the JVM ignores it when it sets
security properties from a security properties file, insert the number sign (#) at the beginning of
the line.
By default, the master security properties file contains many comments that describe in detail
the security properties specified in it. Sometimes, these security properties themselves are
commented out. These security properties that are commented out might have a value
specified or no value at all.
Note
A security property that has been set to no value is set to the empty string. A security
property that has been commented out is set to a null value. In this case, the security
property might be assigned a default value. The comments in the master security
properties file should specify whether a security property has a default value.
[Link]("propertyName," "propertyValue");
For example, a call to the setProperty() method corresponding to the previous example for
specifying the key manager factory algorithm name would be:
[Link]("[Link]", "MyX509");
Note
Some security properties cannot be set dynamically if they have already been read
from a security properties file and cached, which happens when the
[Link] class is initialized. No exception will be thrown if your
code attempts to do this.
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
Introduction
Since the inception of Java technology, there has been strong and growing interest around the
security of the Java platform as well as new security issues raised by the deployment of Java
technology.
From a technology provider's point of view, Java security includes two aspects:
• Provide the Java platform as a secure, ready-built platform on which to run Java-enabled
applications in a secure fashion.
• Provide security tools and services implemented in the Java programming language that
enable a wider range of security-sensitive applications, for example, in the enterprise
world.
This document discusses issues related to the first aspect, where the customers for such
technologies include vendors that bundle or embed Java technology in their products (such as
browsers and operating systems).
The sandbox model was deployed through the Java Development Kit (JDK), and was generally
adopted by applications built with JDK 1.0, including Java-enabled web browsers.
Overall security is enforced through a number of mechanisms. First of all, the language is
designed to be type-safe and easy to use. The hope is that the burden on the programmer is
such that the likelihood of making subtle mistakes is lessened compared with using other
programming languages such as C or C++. Language features such as automatic memory
management, garbage collection, and range checking on strings and arrays are examples of
how the language helps the programmer to write safe code.
Second, compilers and a bytecode verifier ensure that only legitimate Java bytecodes are
executed. The bytecode verifier, together with the Java Virtual Machine, guarantees language
safety at run time.
Moreover, a classloader defines a local name space, which can be used to ensure that an
untrusted applet cannot interfere with the running of other programs.
Finally, access to crucial system resources is mediated by the Java Virtual Machine and is
checked in advance by a SecurityManager class that restricts the actions of a piece of
untrusted code to the bare minimum.
JDK 1.1 introduced the concept of a "signed applet", as illustrated in Figure 1-6. In that
release, a correctly digitally signed applet is treated as if it is trusted local code if the signature
key is recognized as trusted by the end system that receives the applet. Signed applets,
together with their signatures, are delivered in the JAR (Java Archive) format. In JDK 1.1,
unsigned applets still run in the sandbox.
in the SecurityManager class needs to be created in most cases. (In fact, we have so
far not encountered a situation where a new method must be created.)
• Extension of security checks to all Java programs, including applications as well as
applets.
There is no longer a built-in concept that all local code is trusted. Instead, local code (e.g.,
non-system code, application packages installed on the local file system) is subjected to
the same security control as applets, although it is possible, if desired, to declare that the
policy on local code (or remote code) be the most liberal, thus enabling such code to
effectively run as totally trusted. The same principle applies to signed applets and any Java
application.
Finally, an implicit goal is to make internal adjustment to the design of security classes
(including the SecurityManager and ClassLoader classes) to reduce the risks of
creating subtle security holes in future programming.
A domain conceptually encloses a set of classes whose instances are granted the same set of
permissions. Protection domains are determined by the policy currently in effect. The Java
application environment maintains a mapping from code (classes and instances) to their
protection domains and then to their permissions, as illustrated in Figure 1-9.
A thread of execution (which is often, but not necessarily tied to, a single Java thread, which in
turn is not necessarily tied to the thread concept of the underlying operation system) may occur
completely within a single protection domain or may involve an application domain and also the
system domain. For example, an application that prints a message out will have to interact with
the system domain that is the only access point to an output stream. In this case, it is crucial
that at any time the application domain does not gain additional permissions by calling the
system domain. Otherwise, there can be serious security implications.
In the reverse situation where a system domain invokes a method from an application domain,
such as when the AWT system domain calls an applet's paint method to display the applet, it is
again crucial that at any time the effective access rights are the same as current rights enabled
in the application domain.
In other words, a less "powerful" domain cannot gain additional permissions as a result of
calling or being called by a more powerful domain.
This discussion of one thread involving two protection domains naturally generalizes to a
thread that traverses multiple protection domains. A simple and prudent rule of thumb for
calculating permissions is the following:
• The permission set of an execution thread is considered to be the intersection of the
permissions of all protection domains traversed by the execution thread.
• When a piece of code calls the doPrivileged method, the permission set of the
execution thread is considered to include a permission if it is allowed by the said code's
protection domain and by all protection domains that are called or entered directly or
indirectly subsequently.
As you can see, the doPrivileged method enables a piece of trusted code to temporarily
enable access to more resources than are available directly to the application that called it.
This is necessary in some situations. For example, an application may not be allowed direct
access to files that contain fonts, but the system utility to display a document must obtain those
fonts, on behalf of the user. We provide the doPrivileged method for the system domain to
deal with this situation, and the method is in fact available to all domains.
During execution, when access to a critical system resource (such as file I/O and network I/O)
is requested, the resource-handling code directly or indirectly invokes a special
AccessController class method that evaluates the request and decides if the request
should be granted or denied.
Such an evaluation follows and generalizes the "rule of thumb" given previously. The actual
way in which the evaluation is conducted can vary between implementations. The basic
principle is to examine the call history and the permissions granted to the relevant protection
domains, and to return silently if the request is granted or throw a security exception if the
request is denied.
Finally, each domain (system or application) may also implement additional protection of its
internal resources within its own domain boundary. For example, a banking application may
need to support and protect internal concepts such as checking accounts, deposits and
withdrawals. Because the semantics of such protection is unlikely to be predictable or
enforceable by the JDK, the protection system at this level is best left to the system or
application developers. Nevertheless, whenever appropriate, we provide helpful primitives to
simplify developers' tasks. One such primitive is the SignedObject class, whose detail we
will describe later.
New permissions are subclassed either from the Permission class or one of its subclasses,
such as [Link]. Subclassed permissions (other than
BasicPermission) generally belong to their own packages. Thus, FilePermission is
found in the [Link] package.
A crucial abstract method that needs to be implemented for each new class of permission is
the implies method. Basically, "a implies b" means that if one is granted permission "a", one is
naturally granted permission "b". This is important when making access control decisions.
Associated with the abstract class [Link] are the abstract class
named [Link] and the final class
[Link].
[Link]
This abstract class is the ancestor of all permissions. It defines the essential functionalities
required for all permissions.
Each permission instance is typically generated by passing one or more string parameters to
the constructor. In a common case with two parameters, the first parameter is usually "the
name of the target" (such as the name of a file for which the permission is aimed), and the
second parameter is the action (such as "read" action on a file). Generally, a set of actions can
be specified together as a comma-separated composite string.
[Link]
This class holds a homogeneous collection of permissions. In other words, each instance of
the class holds only permissions of the same type.
[Link]
This class is designed to hold a heterogeneous collection of permissions. Basically, it is a
collection of [Link] objects.
[Link]
Recall that the internal state of a security policy is normally expressed by the permission
objects that are associated with each code source. Given the dynamic nature of Java
technology, however, it is possible that when the policy is initialized the actual code that
implements a particular permission class has not yet been loaded and defined in the Java
application environment. For example, a referenced permission class may be in a JAR file that
will later be loaded.
The UnresolvedPermission class is used to hold such "unresolved" permissions. Similarly,
the class [Link] stores a collection of
UnresolvedPermission permissions.
During access control checking on a permission of a type that was previously unresolved, but
whose class has since been loaded, the unresolved permission is "resolved" and the
appropriate access control decision is made. That is, a new object of the appropriate class type
is instantiated, if possible, based on the information in the UnresolvedPermission. This
new object replaces the UnresolvedPermission, which is removed. If the permission is still
unresolvable at this time, the permission is considered invalid, as if it is never granted in a
security policy.
[Link]
The targets for this class can be specified in the following ways, where directory and file names
are strings that cannot contain white spaces.
file
directory (same as directory/)
directory/file
directory/* (all files in this directory)
* (all files in the current directory)
directory/- (all files in the file system under this directory)
- (all files in the file system under the current directory)
"<<ALL FILES>>" (all files in the file system)
Note that <<ALL FILES>> is a special string denoting all files in the system. On Linux or
macOS, this includes all files under the root directory. On Windows, this includes all files on all
drives.
The actions are: read, write, delete, and execute. Therefore, the following are valid code
samples for creating file permissions:
import [Link];
The implies method in this class correctly interprets the file system. For example,
FilePermission("/-", "read,execute") implies FilePermission("/home/gong/
public_html/[Link]", "read"), and FilePermission("bin/*", "execute") implies
FilePermission("bin/emacs19.31", "execute").
Note
Most of these strings are given in platform-dependent format. For example, to
represent read access to the file named foo in the temp directory on the C drive of a
Windows system, you would use
The double backslashes are necessary to represent a single backslash because the
strings are processed by a tokenizer ([Link]), which allows \
to be used as an escape string (e.g., \n to indicate a new line) and which thus requires
two backslashes to indicate a single backslash. After the tokenizer has processed the
FilePermission target string, converting double backslashes to single backslashes,
the end result is the actual path:
"c:\temp\foo"
means you are only giving permission to list the files in that directory, not read any of
them. To allow read access to files, you must specify either an explicit file name, or an
* or -, as in
And finally, note that code always automatically has permission to read files from its
same (URL) location, and subdirectories of that location; it does not need explicit
permission to do so.
[Link]
This class represents access to a network via sockets. The target for this class can be given as
hostname:port_range, where hostname can be given in the following ways:
[Link]
*.domain (all hosts in the domain)
*.[Link]
* (all hosts)
That is, the host is expressed as a DNS name, as a numerical IP address, as "localhost" (for
the local machine) or as "" (which is equivalent to specifying "localhost").
The wildcard * may be included once in a DNS name host specification. If it is included, it must
be in the leftmost position, as in *.[Link].
N (a single port)
N- (all ports numbered N and above)
-N (all ports numbered N and below)
N1-N2 (all ports between N1 and N2, inclusive)
Here N, N1, and N2 are non-negative integers ranging from 0 to 65535 (216-1).
The actions on sockets are accept, connect, listen, and resolve (which is basically DNS
lookup). Note that implicitly, the action "resolve" is implied by "accept", "connect", and "listen" –
i.e., those who can listen or accept incoming connections from or initiate out-going connections
to a host should be able to look up the name of the remote host.
The following are some examples of socket permissions.
import [Link];
Note
SocketPermission("[Link],8080","accept") and
SocketPermission("[Link],[Link]","accept") are not
valid socket permissions.
Moreover, because listen is an action that applies only to ports on the local host,
whereas accept is an action that applies to ports on both the local and remote host,
both actions are necessary.
[Link]
The BasicPermission class extends the Permission class. It can be used as the base
class for permissions that want to follow the same naming convention as BasicPermission.
The name for a BasicPermission is the name of the given permission (for example,
"exitVM", "setFactory", "queuePrintJob", etc). The naming convention follows the hierarchical
property naming convention. An asterisk may appear at the end of the name, following a ".", or
by itself, to signify a wildcard match. For example: "java.*" or "*" is valid, "*java" or "a*b" is not
valid.
The action string (inherited from Permission) is unused. Thus, BasicPermission is
commonly used as the base class for "named" permissions (ones that contain a name but no
actions list; you either have the named permission or you don't.) Subclasses may implement
actions on top of BasicPermission, if desired.
[Link]
The targets for this class are basically the names of Java properties as set in various property
files. Examples are the [Link] and [Link] properties. Targets can be specified as "*" (any
property), "a.*" (any property whose name has a prefix "a."), "a.b.*", and so on. Note that the
wildcard can occur only once and can only be at the rightmost position.
This is one of the BasicPermission subclasses that implements actions on top of
BasicPermission. The actions are read and write. Their meaning is defined as follows:
"read" permission allows the getProperty method in [Link] to be called to get
the property value, and "write" permission allows the setProperty method to be called to set
the property value.
[Link]
The target for a RuntimePermission can be represented by any string, and there is no
action associated with the targets. For example, RuntimePermission("exitVM") denotes the
permission to exit the Java Virtual Machine.
The target names are:
createClassLoader
getClassLoader
setContextClassLoader
setSecurityManager
createSecurityManager
exitVM
setFactory
setIO
modifyThread
modifyThreadGroup
getProtectionDomain
readFileDescriptor
writeFileDescriptor
loadLibrary.{library name}
accessClassInPackage.{package name}
defineClassInPackage.{package name}
accessDeclaredMembers.{class name}
queuePrintJob
[Link]
This is in the same spirit as the RuntimePermission; it's a permission without actions. The
targets for this class are:
accessClipboard
accessEventQueue
listenToAllAWTEvents
showWindowWithoutWarningBanner
[Link]
This class contains the following targets and no actions:
requestPasswordAuthentication
setDefaultAuthenticator
specifyStreamHandler
[Link]
This is the Permission class for reflective operations. A ReflectPermission is a named
permission (like RuntimePermission) and has no actions. The only name currently defined
is suppressAccessChecks, which allows suppressing the standard Java programming language
access checks – for public, default (package) access, protected, and private members –
performed by reflected objects at their point of use.
[Link]
This class contains the following targets and no actions:
enableSubclassImplementation
enableSubstitution
[Link]
SecurityPermissions control access to security-related objects, such as Security,
Policy, Provider, Signer, and Identity objects. This class contains the following targets
and no actions:
getPolicy
setPolicy
getProperty.{key}
setProperty.{key}
insertProvider.{provider name}
removeProvider.{provider name}
setSystemScope
setIdentityPublicKey
setIdentityInfo
printIdentity
addIdentityCertificate
removeIdentityCertificate
clearProviderProperties.{provider name}
putProviderProperty.{provider name}
removeProviderProperty.{provider name}
getSignerPrivateKey
setSignerKeyPair
[Link]
This permission implies all permissions. It is introduced to simplify the work of system
administrators who might need to perform multiple tasks that require all (or numerous)
permissions. It would be inconvenient to require the security policy to iterate through all
permissions. Note that AllPermission also implies new permissions that are defined in the
future.
Clearly, much caution is necessary when considering granting this permission.
[Link]
AuthPermission handles authentication permissions and authentication-related object such
as Subject, SubjectDomainCombiner, LoginContext, and Configuration. This class
contains the following targets and no actions:
doAs
doAsPrivileged
getSubject
getSubjectFromDomainCombiner
setReadOnly
modifyPrincipals
modifyPublicCredentials
modifyPrivateCredentials
refreshCredential
destroyCredential
createLoginContext.{name}
getLoginConfiguration
setLoginConfiguration
refreshLoginConfiguration
There is another layer of implication that may not be immediately obvious to some readers.
Suppose that one applet has been granted the permission to write to the entire file system.
This presumably allows the applet to replace the system binary, including the JVM runtime
environment. This effectively means that the applet has been granted all permissions.
Another example is that if an applet is granted the runtime permission to create class loaders,
it is effectively granted many more permissions, as a class loader can perform sensitive
operations.
Other permissions that are "dangerous" to give out include those that allow the setting of
system properties, runtime permissions for defining packages and for loading native code
libraries (because the Java security architecture is not designed to and does not prevent
malicious behavior at the level of native code), and of course the AllPermission.
For more information about permissions, including tables enumerating the risks of assigning
specific permissions as well as a table of all the JDK built-in methods that require permissions,
see Permissions in the JDK.
To create a new permission, the following steps are recommended, as shown by an example.
Suppose an application developer from company ABC wants to create a customized
permission to "watch TV".
First, create a new class [Link] that extends the abstract class
[Link] (or one of its subclasses), and another new class
[Link] that extends the [Link]. Make sure that the implies
method, among others, is correctly implemented. (Of course, [Link] can
directly extend [Link]; the intermediate [Link] is not
required.)
In the application's resource management code, when checking to see if a permission should
be granted, call AccessController's checkPermission method using a
[Link] object as the parameter.
Note that, when adding a new permission, one should create a new (permission) class and not
add a new method to the security manager. (In the past, in order to enable checking of a new
type of access, you had to add a new method to the SecurityManager class.)
[Link]
This class extends the concept of a codebase within HTML to encapsulate not only the code
location (URL) but also the certificate(s) containing public keys that should be used to verify
signed code originating from that location. Note that this is not the equivalent of the CodeBase
tag in HTML files. Each certificate is represented as a
[Link], and each URL as a [Link].
[Link]
The system security policy for a Java application environment, specifying which permissions
are available for code from various sources, is represented by a Policy object. More
specifically, it is represented by a Policy subclass providing an implementation of the abstract
methods in the Policy class.
There could be multiple instances of the Policy object, although only one is "in effect" at any
time. The currently-installed Policy object can be obtained by calling the getPolicy method,
and it can be changed by a call to the setPolicy method (by code with permission to reset the
Policy).
The source location for the policy information utilized by the Policy object is up to the Policy
implementation. The policy configuration may be stored, for example, as a flat ASCII file, as a
serialized binary file of the Policy class, or as a database. There is a Policy reference
implementation that obtains its information from static policy configuration files.
Here, some_keystore_url specifies the URL location of the keystore, and keystore_type
specifies the keystore type. The latter is optional. If not specified, the type is assumed to be
that specified by the [Link] property in the security properties file.
The URL is relative to the policy file location. Thus if the policy file is specified in the security
properties file as:
[Link].1=[Link]
keystore ".keystore";
[Link]
beginning of a new permission in the entry. Each grant entry grants a set of permissions to a
specified code source and principals.
White spaces are allowed immediately before or after any comma. The name of the permission
class must be a fully qualified class name, such as [Link], and cannot
be abbreviated (for example, to FilePermission).
Note that the action field is optional in that it can be omitted if the permission class does not
require it. If it is present, then it must come immediately after the target field.
The exact meaning of a CodeBase URL value depends on the characters at the end. A
CodeBase with a trailing "/" matches all class files (not JAR files) in the specified directory. A
CodeBase with a trailing "/*" matches all files (both class and JAR files) contained in that
directory. A CodeBase with a trailing "/-" matches all files (both class and JAR files) in the
directory and recursively all files in subdirectories contained in that directory.
The CodeBase field (URL) is optional in that, if it is omitted, it signifies "any code base".
The first signer name field is a string alias that is mapped, via a separate mechanism, to a set
of public keys (within certificates in the keystore) that are associated with the signers. These
keys are used to verify that certain signed classes are really signed by these signers.
This signer field can be a comma-separated string containing names of multiple signers, an
example of which is Adam,Eve,Charles, which means signed by Adam and Eve and Charles
(i.e., the relationship is AND, not OR).
This field is optional in that, if it is omitted, it signifies "any signer", or in other words, "It doesn't
matter whether the code is signed or not".
The second signer field, inside a permission entry, represents the alias to the keystore entry
containing the public key corresponding to the private key used to sign the bytecodes that
implemented the said permission class. This permission entry is effective (i.e., access control
permission will be granted based on this entry) only if the bytecode implementation is verified
to be correctly signed by the said alias.
A principal value specifies a class_name/principal_name pair which must be present within the
executing threads principal set. The principal set is associated with the executing code by way
of a Subject. The principal field is optional in that, if it is omitted, it signifies "any principals".
Note
Regarding keystore alias replacement: If the principal class_name/principal_name pair
is specified as a single quoted string, it is treated as a keystore alias. The keystore is
consulted and queried (via the alias) for an X509 Certificate. If one is found, the
principal_class is automatically treated as
[Link].x500.X500Principal, and the principal_name is
automatically treated as the subject distinguished name from the certificate. If an X509
Certificate mapping is not found, the entire grant entry is ignored.
The order between the CodeBase, SignedBy, and Principal fields does not matter.
The following is an informal BNF grammar for the policy file format, where non-capitalized
terms are terminals:
Now we give some examples. The following policy grants permission [Link] to code signed
by Roland:
The following grants a FilePermission to all code (regardless of the signer and/or
CodeBase):
grant {
permission [Link] ".tmp", "read";
};
The following grants two permissions to code that is signed by both Li and Roland:
The following grants two permissions to code that is signed by Li and that comes from http://
[Link]:
The following grants two permissions to code that is signed by both Li and Roland, and only if
the bytecodes implementing [Link] are genuinely signed by Li.
The reason for including the second signer field is to prevent spoofing when a permission class
does not reside with the Java runtime installation. For example, a copy of the
[Link] class can be downloaded as part of a remote JAR archive, and the
user policy might include an entry that refers to it. Because the archive is not long-lived, the
second time the [Link] class is downloaded, possibly from a different web
site, it is crucial that the second copy is authentic, as the presence of the permission entry in
the user policy might reflect the user's confidence or belief in the first copy of the class
bytecode.
The reason we chose to use digital signatures to ensure authenticity, rather than storing (a
hash value of) the first copy of the bytecodes and using it to compare with the second copy, is
because the author of the permission class can legitimately update the class file to reflect a
new design or implementation.
Note
The strings for a file path must be specified in a platform-dependent format; this is
necessary until there is a universal file description language. The previous examples
have shown strings appropriate on Linux or macOS. On Windows, when you directly
specify a file path in a string, you need to include two backslashes for each actual
single backslash in the path, as in
"C:\users\Cathy\*"
This permits any code executing as the X500Principal, cn=Alice, permission to read and
write to /home/Alice.
The following example shows a grant statement with both codesource and principal
information.
This allows code downloaded from [Link], signed by Duke, and executed by
cn=Alice, permission to read and write into the /tmp/games directory.
keystore "[Link]
will expand ${[Link]} to use the value of the [Link] system property. If that property's
value is /home/cathy, then the previous example is equivalent to
In order to assist in platform-independent policy files, you can also use the special notation of $
{/}, which is a shortcut for ${[Link]}. This allows permission designations such as
If [Link] is /home/cathy, and you are on Linux, the previous example gets converted to:
If on the other hand [Link] is C:\users\cathy and you are on a Windows system, the
previous example gets converted to:
then any [Link] characters will be automatically converted to slashes (/), which is
desirable since codebases are URLs. Thus on a Windows system, even if [Link] is set to
C:\j2sdk1.2, the previous example would get converted to
Thus you don't need to use ${/} in codebase strings (and you shouldn't).
Property expansion takes place anywhere a double quoted string is allowed in the policy file.
This includes the signedby, codebase, target names, and action fields.
Please note: You can't use nested properties; they will not work. For example,
"${user.${foo}}"
doesn't work, even if the foo property is set to home. The reason is the property parser doesn't
recognize nested properties; it simply looks for the first ${, and then keeps looking until it finds
the first } and tries to interpret the result ${user.$foo} as a property, but fails if there is no
such property.
Also note: If a property can't be expanded in a grant entry, permission entry, or keystore entry,
that entry is ignored. For example, if the system property foo is not defined and you have:
then all the permissions in this grant entry are ignored. If you have
grant {
permission Foo "${foo}";
permission Bar;
};
then only the permission Foo "${foo}"; entry is ignored. And finally, if you have
keystore "${foo}";
"C:\\users\\cathy\\[Link]"
"C:\users\cathy\[Link]"
Expansion of a property in a string takes place after the tokenizer has processed the string.
Thus if you have the string
"${[Link]}\\[Link]"
then first the tokenizer processes the string, converting the double backslashes to a single
backslash, and the result is
"${[Link]}\[Link]"
"C:\users\cathy\[Link]"
"${[Link]}${/}[Link]"
There are two protocols supported in the default policy file implementation:
1. ${{self}}
The protocol, self, denotes a replacement of the entire string, ${{self}}, with one or
more principal class/name pairs. The exact replacement performed depends upon the
contents of the grant clause to which the permission belongs.
If the grant clause does not contain any principal information, the permission will be
ignored (permissions containing ${{self}} in their target names are only valid in the
context of a principal-based grant clause). For example, BarPermission will always be
ignored in the following grant clause:
If the grant clause contains principal information, ${{self}} will be replaced with that
same principal information. For example, ${{self}} in BarPermission will be replaced by
[Link].x500.X500Principal "cn=Duke" in the following grant clause:
If there is a comma-separated list of principals in the grant clause, then ${{self}} will be
replaced by the same comma-separated list or principals. In the case where both the
principal class and name are wildcarded in the grant clause, ${{self}} is replaced with all
the principals associated with the Subject in the current AccessControlContext.
The following example describes a scenario involving both self and KeyStore alias
replacement together:
keystore "[Link]
keystore "[Link]
In the previous example the X.509 certificate associated with the alias, duke, is retrieved
from the KeyStore, [Link]/blah/.keystore. Assuming duke's certificate
specifies "o=dukeOrg, cn=duke" as the subject distinguished name, then $
{{alias:duke}} is replaced with [Link].x500.X500Principal
"o=dukeOrg, cn=duke".
The permission entry is ignored under the following error conditions:
• The keystore entry is unspecified
• The alias_name is not provided
• The certificate for alias_name cannot be retrieved
• The certificate retrieved is not an X.509 certificate
Assigning Permissions
When a principal executes a class that originated from a particular CodeSource, the security
mechanism consults the policy object to determine what permissions to grant. This is done by
invoking the getPermissions or implies method on the Policy object that is installed in the
VM.
Clearly, a given code source in a ProtectionDomain can match the code source given in
multiple entries in the policy, for example because the wildcard (*) is allowed.
The following algorithm is used to locate the appropriate set of permissions in the policy.
1. Match the public keys, if code is signed.
If multiple entries are matched, then all the permissions given in those entries are granted. In
other words, permission assignment is additive. For example, if code signed with key A gets
permission X and code signed by key B gets permission Y and no particular codebase is
specified, then code signed by both A and B gets permissions X and Y. Similarly, if code with
codeBase "[Link] is given permission X, and "[Link]
people/*" is given permission Y, and no particular signers are specified, then an applet from
"[Link] gets both X and Y.
Note that URL matching here is purely syntactic. For example, a policy can give an entry that
specifies a URL "[Link] Such an entry is useful only when one can obtain
Java code directly from ftp for execution.
To specify URLs for the local file system, a file URL can be used. For example, to specify files
in the /home/cathy/temp directory on Linux, you'd use
"file:/home/cathy/temp/*"
"file:/c:/temp/*"
Note: codeBase URLs always use slashes (no backlashes), regardless of the platform they
apply to.
You can also use an absolute path name such as
"/home/gong/bin/MyWonderfulJava"
default a single system-wide policy file, and a single user policy file. The system policy file is by
default located at
• {[Link]}/conf/security/[Link] (Linux and macOS)
• {[Link]}\conf\security\[Link] (Windows)
Here, [Link] is a system property specifying the directory into which the JDK was installed.
The user policy file is by default located at
• {[Link]}/.[Link] (Linux and macOS)
• {[Link]}\.[Link] (Windows)
Here, [Link] is a system property specifying the user's home directory.
When the Policy is initialized, the system policy is loaded in first, and then the user policy is
added to it. If neither policy is present, a built-in policy is used. This built-in policy is the same
as the original sandbox policy. Policy file locations are specified in the security properties file,
which is located at
• {[Link]}/conf/security/[Link] (Linux and macOS)
• {[Link]}\conf\security\[Link] (Windows)
The policy file locations are specified as the values of properties whose names are of the form
[Link].n
Here, n is a number. You specify each such property value in a line of the following form:
[Link].n=URL
Here, URL is a URL specification. For example, the default system and user policy files are
defined in the security properties file as
[Link].1=file:${[Link]}/conf/security/[Link]
[Link].2=file:${[Link]}/.[Link]
You can actually specify a number of URLs, including ones of the form "[Link] and all the
designated policy files will get loaded. You can also comment out or change the second one to
disable reading the default user policy file.
The algorithm starts at [Link].1, and keeps incrementing until it does not find a URL.
Thus if you have [Link].1 and [Link].3, [Link].3 will never be read.
It is also possible to specify an additional or a different policy file when invoking execution of an
application. This can be done via the -[Link] command-line argument, which
sets the value of the [Link] property. For example, consider the following
example:
Here, pURL is a URL specifying the location of a policy file, then the specified policy file will be
loaded in addition to all the policy files that are specified in the security properties file. (The -
[Link] argument ensures that the default security manager is installed, and
thus the application is subject to policy checks, as described in Managing Applets and
Applications. It is not required if the application SomeApp installs a security manager.)
If you use the following, with a double equals sign (==), then just the specified policy file will be
used; all others will be ignored.
Note
• Properties in the [Link] file are typically parsed only once. If you have
modified any property in this file, restart your applications to ensure that the
changes are properly reflected.
• Use the double equals sign (==) with the [Link] property with
care as it overrides the built-in JDK policy file, which grants a set of default
permissions that are designed to provide a secure, out-of-the-box configuration for
the JDK. Overriding this policy may result in unexpected behavior (JDK code may
not be granted the right permissions) and should only be done by experienced
users.
• The -[Link] policy file value will be ignored (for both java and
appletviewer commands) if the [Link] property in the
security properties file is set to false. The default is true.
[Link]=[Link]
To customize, you can change the property value to specify another class, as in
[Link]=[Link]
[Link]
This is an exception class that is a subclass of [Link]. The intention is that
there should be two types of exceptions associated with security and the security packages.
[Link]
The AccessController class is used for the following three purposes:
For example, the typical way to invoke access control has been the following code (taken from
an earlier version of the JDK):
Under the current architecture, the check typically should be invoked whether or not there is a
classloader associated with a calling class. It could be simply, for example:
Note that there are (legacy) cases, for example, in some browsers, where whether there is a
SecurityManager installed signifies one or the other security state that may result in
different actions being taken. For backward compatibility, the checkPermission method on
SecurityManager can be used.
We currently do not change this aspect of the SecurityManager usage, but would
encourage application developers to use new techniques introduced in the JDK in their future
programming when the built-in access control algorithm is appropriate.
The default behavior of the SecurityManager checkPermission method is actually to call the
AccessController checkPermission method. A different SecurityManager
implementation may implement its own security management approach, possibly including the
addition of further constraints used in determining whether or not an access is permitted.
Figure 1-11 Multiple Method Calls that Cross Protection Domain Boundaries
When the checkPermission method of the AccessController is invoked by the most recent
caller (e.g., a method in the File class), the basic algorithm for deciding whether to allow or
deny the requested access is as follows.
If any caller in the call chain does not have the requested permission,
AccessControlException is thrown, unless the following is true – a caller whose domain is
granted the said permission has been marked as "privileged" (see the next section) and all
parties subsequently called by this caller (directly or indirectly) all have the said permission.
There are obviously two implementation strategies:
• In an "eager evaluation" implementation, whenever a thread enters a new protection
domain or exits from one, the set of effective permissions is updated dynamically.
The benefit is that checking whether a permission is allowed is simplified and can be faster
in many cases. The disadvantage is that, because permission checking occurs much less
frequently than cross-domain calls, a large percentage of permission updates are likely to
be useless effort.
• In a "lazy evaluation" implementation, whenever permission checking is requested, the
thread state (as reflected by the current state, including the current thread's call stack or its
equivalent) is examined and a decision is reached to either deny or grant the particular
access requested.
One potential downside of this approach is performance penalty at permission checking
time, although this penalty would have been incurred anyway in the "eager evaluation"
approach (albeit at earlier times and spread out among each cross-domain call). Our
implementation so far has yielded acceptable performance, so we feel that lazy evaluation
is the most economical approach overall.
Therefore, the algorithm for checking permissions is currently implemented as "lazy
evaluation". Suppose the current thread traversed m callers, in the order of caller 1 to caller 2
to caller m. Then caller m invoked the checkPermission method. The basic algorithm
checkPermission uses to determine whether access is granted or denied is the following (see
subsequent sections for refinements):
// Next, check the context inherited when the thread was created.
// Whenever a new thread is created, the AccessControlContext at
// that time is stored and associated with the new thread, as the
// "inherited" context.
[Link](permission);
Handling Privileges
A static method in the AccessController class allows code in a class instance to inform the
AccessController that a body of its code is "privileged" in that it is solely responsible for
requesting access to its available resources, no matter what code caused it to do so.
That is, a caller can be marked as being "privileged" when it calls the doPrivileged method.
When making access control decisions, the checkPermission method stops checking if it
reaches a caller that was marked as "privileged" via a doPrivileged call without a context
argument (see a subsequent section for information about a context argument). If that caller's
domain has the specified permission, no further checking is done and checkPermission
returns quietly, indicating that the requested access is allowed. If that domain does not have
the specified permission, an exception is thrown, as usual.
The normal use of the "privileged" feature is as follows:
If you don't need to return a value from within the "privileged" block, do the following:
somemethod() {
...normal code here...
[Link](new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
[Link]("awt");
return null; // nothing to return
}
});
...normal code here...
}
PrivilegedAction is an interface with a single method, named run, that returns an Object.
This example shows creation of an anonymous inner class implementing that interface; a
concrete implementation of the run method is supplied. When the call to doPrivileged is
made, an instance of the PrivilegedAction implementation is passed to it. The doPrivileged
method calls the run method from the PrivilegedAction implementation after enabling
privileges, and returns the run method's return value as the doPrivileged return value, which
is ignored in this example. (For more information about inner classes, see Nested Classes in
the Java Tutorials.
If you need to return a value, you can do something like the following:
somemethod() {
...normal code here...
String user = (String) [Link](
new PrivilegedAction() {
public Object run() {
return [Link]("[Link]");
}
}
);
...normal code here...
}
If the action performed in your run method could throw a "checked" exception (one listed in the
throws clause of a method), then you need to use the PrivilegedExceptionAction interface
instead of the PrivilegedAction interface:
Some important points about being privileged: Firstly, this concept only exists within a single
thread. As soon as the privileged code completes, the privilege is guaranteed to be erased or
revoked.
Secondly, in this example, the body of code in the run method is privileged. However, if it calls
less trustworthy code that is less privileged, that code will not gain any privileges as a result; a
permission is only granted if the privileged code has the permission and so do all the
subsequent callers in the call chain up to the checkPermission call.
}
} else
return;
}
}
// Next, check the context inherited when the thread was created.
// Whenever a new thread is created, the AccessControlContext at
// that time is stored and associated with the new thread, as the
// "inherited" context.
[Link](permission);
Note that this inheritance is transitive so that, for example, a grandchild inherits both from the
parent and the grandparent. Also note that the inherited context snapshot is taken when the
new child is created, and not when the child is first run. There is no public API change for the
inheritance feature.
[Link]
Recall that the AccessController checkPermission method performs security checks
within the context of the current execution thread (including the inherited context). A difficulty
arises when such a security check can only be done in a different context. That is, sometimes
a security check that should be made within a given context will actually need to be done from
within a different context. For example, when one thread posts an event to another thread, the
second thread serving the requesting event would not have the proper context to complete
access control, if the service requests access to controller resources.
To address this issue, we provide the AccessController getContext method and
AccessControlContext class. The getContext method takes a "snapshot" of the current
calling context, and places it in an AccessControlContext object, which it returns. A
sample call is the following:
This context captures relevant information so that an access control decision can be made by
checking, from within a different context, against this context information. For example, one
thread can post a request event to a second thread, while also supplying this context
information. AccessControlContext itself has a checkPermission method that makes
access decisions based on the context it encapsulates, rather than that of the current
execution thread. Thus, the second thread can perform an appropriate security check if
necessary by invoking the following:
[Link](permission);
This method call is equivalent to performing the same security check in the context of the first
thread, even though it is done in the second thread.
There are also times where one or more permissions must be checked against an access
control context, but it is unclear a priori which permissions are to be checked. In these cases
you can use the doPrivileged method that takes a context:
somemethod() {
[Link](new PrivilegedAction() {
// Next, check the context inherited when the thread was created.
// Whenever a new thread is created, the AccessControlContext at
// that time is stored and associated with the new thread, as the
// "inherited" context.
[Link](permission);
between those applet classes. In fact, these applets can contain classes of the same name –
these classes are treated as distinct types by the Java Virtual Machine.
The class loading mechanism is not only central to the dynamic nature of the Java
programming language. It also plays a critical role in providing security because the class
loader is responsible for locating and fetching the class file, consulting the security policy, and
defining the class object with the appropriate permissions.
When creating a custom class loader class, one can subclass from any of the previous class
loader classes, depending on the particular needs of the custom class loader.
Observe that it is critical for type safety that the same class not be loaded more than once by
the same class loader. If the class is not among those already loaded, the current class loader
attempts to delegate the task to the parent class loader. This can occur recursively. This
ensures that the appropriate class loader is used. For example, when locating a system class,
the delegation process continues until the system class loader is reached.
We have seen the delegation algorithm earlier. But, given the name of any class, which class
loader do we start with in trying to load the class? The rules for determining the class loader
are the following:
• When loading the first class of an application, a new instance of the URLClassLoader is
used.
• When loading the first class of an applet, a new instance of the AppletClassLoader is
used.
• When [Link] is directly called, the primordial class loader is used.
• If the request to load a class is triggered by a reference to it from an existing class, the
class loader for the existing class is asked to load the class.
Note that rules about the use of URLClassLoader and AppletClassLoader instances have
exceptions and can vary depending on the particular system environment. For example, a web
browser may choose to reuse an existing AppletClassLoader to load applet classes from
the same web page.
Due to the power of class loaders, we severely restrict who can create class loader instances.
On the other hand, it is desirable to provide a convenient mechanism for applications or
applets to specify URL locations and load classes from them. We provide static methods to
allow any program to create instances of the URLClassLoader class, although not other
types of class loaders.
Security Management
Managing Applets and Applications
Currently, all JDK system code invokes SecurityManager methods to check the policy
currently in effect and perform access control checks. There is typically a security manager
(SecurityManager implementation) installed whenever an applet is running; the
appletviewer and most browsers install a security manager.
A security manager is not automatically installed when an application is running. To apply the
same security policy to an application found on the local file system as to downloaded applets,
either the user running the application must invoke the Java Virtual Machine with the -
[Link] command-line argument (which sets the value of the
[Link] property), as in
or the application itself must call the setSecurityManager method in the [Link]
class to install a security manager.
It is possible to specify on the command line a particular security manager to be utilized, by
following -[Link] with an equals and the name of the class to be used as
the security manager, as in
If no security manager is specified, the built-in default security manager is utilized (unless the
application installs a different security manager). All of the following are equivalent and result in
usage of the default security manager:
The JDK includes a property named [Link]. Classes that are stored on the local file
system but should not be treated as base classes (e.g., classes built into the SDK) should be
on this path. Classes on this path are loaded with a secure class loader and are thus subjected
to the security policy being enforced.
There is also a -[Link] command-line argument whose usage determines
what policy files are utilized. This command-line argument is described in detail in Default
Policy Implementation and Policy File Syntax. Basically, if you don't include -
[Link] on the command line, then the policy files specified in the security
properties file will be used.
You can use a -[Link] command-line argument to specify an additional or a
different policy file when invoking execution of an application. For example, if you type the
following, where pURL is a URL specifying the location of a policy file, then the specified policy
file will be loaded in addition to all the policy files specified in the security properties file:
If you instead type the following command, using a double equals, then just the specified policy
file will be used; all others will be ignored:
One thing to remember is that, when you implement your own SecurityManager, you should
install it as trusted software and grant it [Link]. You can do this by
adjusting the policy file to grant AllPermission to your SecurityManager. For more
information, see Default Policy Implementation and Policy File Syntax.
Auxiliary Tools
This section briefly describes the usage of two tools that assist in the deployment of security
features.
called "alias". This tool also manages certificates (that are "trusted" by the user), which are
stored in the same database as the authentication information, and can be referenced by an
"alias".
keytool stores the keys and certificates in a so-called keystore. The default keystore
implementation implements the keystore as a file. It protects private keys with a password.
The chains of X.509 certificates are provided by organizations called Certification Authorities,
or CAs. Identities (including CAs) use their private keys to authenticate their association with
objects (such as with channels which are secured using SSL), with archives of code they
signed, or (for CAs) with X.509 certificates they have issued. As a bootstrapping tool,
certificates generated using the -gencert option may be used until a Certification Authority
returns a certificate chain.
The private keys in this database are always stored in encrypted form, to make it difficult to
disclose these private keys inappropriately. A password is required to access or modify the
database. These private keys are encrypted using the "password", which should be several
words long. If the password is lost, those authentication keys cannot be recovered.
In fact, each private key in the keystore can be protected using its own individual password,
which may or may not be the same as the password that protects the keystore's overall
integrity.
This tool is (currently) intended to be used from the command line, where one simply types
keytool as a shell prompt. keytool is a script that executes the appropriate Java classes and
is built together with the SDK.
The command line options for each command may be provided in any order. Typing an
incorrect option or typing keytool -help will cause the tool's usage to be summarized on the
output device (such as a shell window).
Note
You can also use the [Link] API to sign JAR files.
The basic idea is that the supplier of the resource can create an object representing the
resource, create a GuardedObject that embeds the resource object inside, and then provide
the GuardedObject to the consumer. In creating the GuardedObject, the supplier also
specifies a Guard object such that anyone (including the consumer) can only obtain the
resource object if certain (security) checks inside the Guard are satisfied.
Guard is an interface, so any object can choose to become a Guard. The only method in this
interface is called checkGuard. It takes an Object argument and it performs certain (security)
checks. The Permission class in [Link] implements the Guard interface.
For example, suppose a system thread is asked to open a file /a/b/[Link] for read access,
but the system thread does not know who the requestor is or under what circumstances the
request is made. Therefore, the correct access control decision cannot be made at the server
side. The system thread can use GuardedObject to delay the access control checking, as
follows.
Now the system thread can pass g to the consumer thread. For that thread to obtain the file
input stream, it has to call
This method in turn invokes the checkGuard method on the Guard object p, and because p is a
Permission, its checkGuard method is in fact:
SecurityManager sm = [Link]();
if (sm != null) [Link](this);
This ensures that a proper access control check takes place within the consumer context. In
fact, one can replace often-used hash tables and access control lists in many cases and simply
store a hash table of GuardedObjects.
This basic pattern of GuardedObject and Guard is very general, and we expect that by
extending the basic Guard and GuardedObject classes, developers can easily obtain quite
powerful access control tools. For example, per-method invocation can be achieved with an
appropriate Guard for each method, and a Guard can check the time of the day, the signer or
other identification of the caller, or any other relevant information.
Note that certain typing information is lost because GuardedObject returns an Object.
GuardedObject is intended to be used between cooperating parties so that the receiving
party should know what type of object to expect (and to cast for). In fact, we envision that most
usage of GuardedObject involves subclassing it (say to form a
GuardedFileInputStream class), thus encapsulating typing information, and casting can
happen suitably in the subclass.
[Link]
This class is an essential building block for other security primitives. SignedObject contains
another Serializable object, the (to-be-)signed object and its signature. If the signature is
not null, it contains a valid digital signature of the signed object. This is illustrated in
Figure 1-13.
The underlying signing algorithm is set through a Signature object as a parameter to the sign
method call, and the algorithm can be, among others, the NIST standard DSA, using DSA and
SHA-256. The algorithm is specified using the same convention for signatures, such as "SHA/
DSA".
The signed object is a "deep copy" (in serialized form) of an original object. Once the copy is
made, further manipulation of the original object has no side effect on the copy. A signed object
is immutable.
A typical example of creating a signed object is the following:
A typical example of verification is the following (having received SignedObject so), where
the first line is not needed if the name of the algorithm is known:
• It can be used to sign and serialize data/object for storage outside the Java runtime (e.g.,
storing critical access control data on disk).
• Nested SignedObjects can be used to construct a logical sequence of signatures,
resembling a chain of authorization and delegation.
It is intended that this class can be subclassed in the future to allow multiple signatures on the
same signed object. In that case, existing method calls in this base class will be fully
compatible in semantics. In particular, any get method will return the unique value if there is
only one signature, and will return an arbitrary one from the set of signatures if there is more
than one signature.
Object-Level Protection
Given the object-oriented nature of the Java programming language, it is conceivable that
developers will benefit from a set of appropriate object-level protection mechanisms that (1)
goes beyond the natural protection provided by the Java programming language and that (2)
supplements the thread-based access control mechanism.
One such mechanism is SignedObject. Another is the SealedObject class, which uses
encryption to hide the content of an object.
GuardedObject is a general way to enforce access control at a per class/object per method
level. This method, however, should be used only selectively, partly because this type of
control can be difficult to administer at a high level.
than the domain of which it is a subpart. A domain could be created, for example, to selectively
further limit what a program can do.
Often a domain is thought of as supporting inheritance: a subdomain would automatically
inherit the parent domain's security attributes, except in certain cases where the parent further
restricts the subdomain explicitly. Relaxing a subdomain by right amplification is a possibility
with the notion of trusted code.
For convenience, we can think of the system domain as a single, big collection of all system
code. For better protection, though, system code should be run in multiple system domains,
where each domain protects a particular type of resource and is given a special set of rights.
For example, if file system code and network system code run in separate domains, where the
former has no rights to the networking resources and the latter has no rights to the file system
resources, the risks and consequence of an error or security flaw in one system domain is
more likely to be confined within its boundary.
PrivilegedAction is a functional interface with a single abstract method, named run, that
returns a value of type specified by its type parameter.
Note that this example ignores the return value of the run method. Also, depending on what
privileged code actually consists of, you might have to make some changes due to the way
inner classes work. For example, if privileged code throws an exception or attempts to access
local variables, then you will have to make some changes, which is described later.
Be very careful in your use of the privileged construct, and always remember to make the
privileged code section as small as possible. That is, try to limit the code within the run method
to only what needs to be run with privileges, and do more general things outside the run
method. Also note that the call to doPrivileged should be made in the code that wants to
enable its privileges. Do not be tempted to write a utility class that itself calls doPrivileged as
that could lead to security holes. You can write utility classes for PrivilegedAction classes
though, as shown in the preceding example. See Guideline 9-3: Safely invoke
[Link] in Secure Coding Guidelines for the Java
Programming Language.
Example 1-1 Sample Code for Privileged Block
• In a class that implements the interface PrivilegedAction.
• In an anonymous class.
• In a lambda expression.
import [Link].*;
}
}
// Become privileged:
[Link](mya);
// Anonymous class
[Link](new PrivilegedAction<Void>() {
public Void run() {
// Privileged code goes here, for example:
[Link]("awt");
return null; // nothing to return
}
});
// Lambda expression
[Link]((PrivilegedAction<Void>)
() -> {
// Privileged code goes here, for example:
[Link]("awt");
return null; // nothing to return
}
);
}
Returning Values
If you need to return a value, then you can do something like the following:
[Link](
[Link]((PrivilegedAction<String>)
() -> [Link]("[Link]")
)
);
For example:
() -> {
[Link](lib);
return null; // nothing to return
}
);
[Link](new PrivilegedAction<Void>() {
public Object run() {
[Link](lib);
return null; // nothing to return
}
});
The variable lib is effectively final because its value has not been modified. For example,
suppose you add the following assignment statement after the declaration of the variable lib:
lib = "swing";
The compiler generates the following errors when it encounters the invocation
[Link] both in the lambda expression and the anonymous class:
String lib;
// The lib variable gets set multiple times so you can't make it
// effectively final.
// Create a final String that you can use inside of the run method
final String fLib = lib;
[Link]((PrivilegedAction<Void>)
() -> {
[Link](fLib);
return null; // nothing to return
}
);
Handling Exceptions
If the action performed in your run method could throw a checked exception (one that must be
listed in the throws clause of a method), then you need to use the
PrivilegedExceptionAction interface instead of the PrivilegedAction interface.
try {
Path path = [Link]().getPath("somefile");
BufferedReader br = [Link](
(PrivilegedExceptionAction<BufferedReader>)
() -> [Link](path)
);
// ... read from file and do something
} catch (PrivilegedActionException e) {
parameter (as in this example), then the invocation of doPrivileged does not perform any
additional security checks.
The third parameter of this version of doPrivileged is of type Permission..., which is a
varargs parameter. This means that you can specify one or more Permission parameters or an
array of Permission objects, as in Permission[]. In this example, the invocation of
doPrivileged can retrieve the properties [Link] and [Link].
You can use this three parameter variant of doPrivileged in a mode of least privilege or a
mode of more privilege.
Least Privilege
The typical use case of the doPrivileged method is to enable the method that invokes it to
perform one or more actions that require permission checks without requiring the callers of the
current method to have all the necessary permissions.
For example, the current method might need to open a file or make a network request for its
own internal implementation purposes.
Before JDK 8, calls to doPrivileged methods had only two parameters. They worked by
granting temporary privileges to the calling method and stopping the normal full traversal of the
stack for access checking when it reached that class, rather than continuing up the call stack
where it might reach a method whose defining class does not have the required permission.
Typically, the class that is calling doPrivileged might have additional permissions that are not
required in that code path and which might also be missing from some caller classes.
Normally, these extra permissions are not exercised at runtime. Not elevating them through
use of doPrivileged helps to block exploitation of any incorrect code that could perform
unintended actions. This is especially true when the PrivilegedAction is more complex than
usual, or when it calls code outside the class or package boundary that might evolve
independently over time.
The three-parameter variant of doPrivileged is generally safer to use because it avoids
unnecessarily elevating permissions that are not intended to be required. However, it executes
less efficiently so simple or performance-critical code paths might choose not to use it.
More Privilege
When coding the current method, you want to temporarily extend the permission of the calling
method to perform an action.
For example, a framework I/O API might have a general purpose method for opening files of a
particular data format. This API would take a normal file path parameter and use it to open an
underlying FileInputStream using the calling code's permissions. However, this might also
allow any caller to open the data files in a special directory that contains some standard
demonstration samples.
The callers of this API could be directly granted a FilePermission for read access. However, it
might not be convenient or possible for the security policy of the calling code to be updated.
For example, the calling code could be a sandboxed applet.
One way to implement this is for the code to check the incoming path and determine if it refers
to a file in the special directory. If it does, then it would call doPrivileged, enabling all
permissions, then open the file inside the PrivilegedAction. If the file was not in the special
directory, the code would open the file without using doPrivileged.
This technique requires the implementation to carefully handle the requested file path to
determine if it refers to the special shared directory. The file path must be canonicalized before
calling doPrivileged so that any relative path will be processed (and permission to read the
[Link] system property will be checked) prior to determining if the path refers to a file in the
special directory. It must also prevent malicious "../" path elements meant to escape out of the
special directory.
A simpler and better implementation would use the variant of doPrivileged with the third
parameter. It would pass a FilePermission with read access to the special directory as the
third parameter. Then any manipulation of the file would be inside the PrivilegedAction. This
implementation is simpler and much less prone to contain a security flaw.
The source location for the policy information used by the Policy object depends on the
Policy implementation. The Policy reference implementation obtains its information from
policy configuration files. See Default Policy Implementation and Policy File Syntax for
information about the Policy reference implementation and the syntax that must be used in
policy files it reads.
A protection domain encompasses a CodeSource instance and the permissions granted to
code from that CodeSource, as determined by the security policy currently in effect. Thus,
classes signed by the same keys and from the same URL are typically placed in the same
domain, and a class belongs to one and only one protection domain. (However, classes signed
by the same keys and from the same URL but loaded by separate class loader instances are
typically placed in separate domains.) Classes that have the same permissions but are from
different code sources belong to different domains.
Classes shipped with the JDK run-time image and loaded by the bootstrap class loader are
granted AllPermission. However, classes shipped with the JDK run-time image and loaded
by the platform class loader are granted permissions as specified by the default policy of the
JDK. Each module's classes are assigned a unique protection domain using the jrt URL
scheme and may only be granted the permissions necessary for them to function correctly, and
not necessarily AllPermission.
Each applet or application runs in its appropriate domain, determined by its code source. For
an applet (or an application running under a security manager) to be allowed to perform a
secured action (such as reading or writing a file), the applet or application must be granted
permission for that particular action.
More specifically, whenever a resource access is attempted, all code traversed by the
execution thread up to that point must have permission for that resource access, unless some
code on the thread has been marked as privileged. That is, suppose that access control
checking occurs in a thread of execution that has a chain of multiple callers. (Think of this as
multiple method calls that potentially cross the protection domain boundaries.) When the
[Link] method is invoked by the most recent caller, the
basic algorithm for deciding whether to allow or deny the requested access is as follows: If the
code for any caller in the call chain does not have the requested permission, then an
AccessControlException is thrown, unless the following is true: a caller whose code is
granted the said permission has been marked as privileged, and all parties subsequently called
by this caller (directly or indirectly) have the said permission.
Note
The method [Link] is normally invoked indirectly
through invocations of specific SecurityManager methods that begin with the word
check such as checkConnect or through the method
[Link]. Normally, these checks only occur if a
SecurityManager has been installed; code checked by the
[Link] method first checks if the method
[Link] returns null.
Marking code as privileged enables a piece of trusted code to temporarily enable access to
more resources than are available directly to the code that called it. This is necessary in some
situations. For example, an application might not be allowed direct access to files that contain
fonts, but the system utility to display a document must obtain those fonts, on behalf of the
user. The system utility must become privileged in order to obtain the fonts.
Reflection
The doPrivileged method can be invoked reflectively using the
[Link] method.
One subtlety that must be considered is the interaction of this API with reflection. The
doPrivileged method can be invoked reflectively using the
[Link] method. In this case, the privileges granted in
privileged mode are not those of [Link] but of the non-reflective code that invoked it.
Otherwise, system privileges could erroneously (or maliciously) be conferred on user code.
Note that similar requirements exist when using reflection in the existing API.
Appendix B: Acknowledgments
The design and implementation of new security features in Java 2 SDK is the work of primarily
members of the JavaSoft security group. Other (past and present) members of the JavaSoft
community provided invaluable insight, detailed reviews, and much needed technical
assistance. Significant contributors, in alphabetical order, include but are not limited to: Gigi
Ankeny, Josh Bloch, Satya Dodda, Charlie Lai, Sheng Liang, Jan Luehe, Marianne Mueller,
Jeff Nisewanger, Hemma Prafullchandra, Roger Riggs, Nakul Saraiya, Bill Shannon, Roland
Schemers, and Vijay Srinivasan.
This work is not possible without strong support from JavaSoft management (our thanks go to
Dick Neiss, Jon Kannegaard, and Alan Baratz), and the testing and documentation groups
(especially Mary Dageforde). We are grateful for technical guidance from James Gosling,
Graham Hamilton, and Jim Mitchell.
We received numerous suggestions from our corporate partners and licensees, whom we
could not fully list here.
Appendix C: References
M. Gasser. Building a Secure Computer System. Van Nostrand Reinhold Co., New York, 1988.
L. Gong, "Java Security: Present and Near Future". IEEE Micro, 17(3):14--19, May/June 1997.
L. Gong, T.M.A. Lomas, R.M. Needham, and J.H. Saltzer, "Protecting Poorly Chosen Secrets
from Guessing Attacks". IEEE Journal on Selected Areas in Communications, 11(5):648--656,
June, 1993.
J. Gosling, Bill Joy, and Guy Steele. The Java Language Specification. Addison-Wesley, Menlo
Park, California, August 1996.
A.K. Jones. Protection in Programmed Systems. Ph.D. dissertation, Carnegie-Mellon
University, Pittsburgh, PA 15213, June 1973.
B.W. Lampson. Protection. In Proceedings of the 5th Princeton Symposium on Information
Sciences and Systems, Princeton University, March 1971. Reprinted in ACM Operating
Systems Review, 8(1):18--24, January, 1974.
T. Lindholm and F. Yellin. The Java Virtual Machine Specification. Addison-Wesley, Menlo
Park, California, 1997.
P.G. Neumann. Computer-Related Risks. Addison-Wesley, Menlo Park, California, 1995.
U.S. General Accounting Office. Information Security: Computer Attacks at Department of
Defense Pose Increasing Risks. Technical Report GAO/AIMD-96-84, Washington, D.C. 20548,
May 1996.
J.H. Saltzer. Protection and the Control of Information Sharing in Multics. Communications of
the ACM, 17(7):388--402, July 1974.
J.H. Saltzer and M.D. Schroeder. The Protection of Information in Computer Systems}.
Proceedings of the IEEE, 63(9):1278--1308, September 1975.
M.D. Schroeder. Cooperation of Mutually Suspicious Subsystems in a Computer Utility. Ph.D.
dissertation, Massachusetts Institute of Technology, Cambridge, MA 02139, September 1972.
W.A. Wulf, R. Levin, and S.P. Harbison. HYDRA/[Link] -- An Experimental Computer System.
McGraw-Hill, 1981.
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
A permission typically has a name (often referred to as a "target name") and, in some cases, a
comma-separated list of one or more actions. For example, the following code creates a
FilePermission object representing read access to the file named abc in the /tmp directory:
Here, the target name is "/tmp/abc" and the action string is "read".
Important
The previous statement creates a permission object. A permission object represents,
but does not grant access to, a system resource. Permission objects are constructed
and assigned ("granted") to code based on the policy in effect. When a permission
object is assigned to some code, that code is granted the permission to access the
system resource specified in the permission object, in the specified manner. A
permission object may also be constructed by the current security manager when
making access decisions. In this case, the (target) permission object is created based
on the requested access, and checked against the permission objects granted to and
held by the code making the request.
The policy for a Java application environment is represented by a Policy object. In the
"JavaPolicy" Policy implementation, the policy can be specified within one or more policy
configuration files. The policy file(s) specify what permissions are allowed for code from
specified code sources. The following is a sample policy file entry that grants code from the /
home/sysadmin directory read access to the file /tmp/abc:
To know more about policy file locations and granting permissions in policy files, see Default
Policy Implementation and Policy File Syntax.
Technically, whenever a resource access is attempted, all code traversed by the execution
thread up to that point must have permission for that resource access, unless some code on
the thread has been marked as "privileged." See Appendix A: API for Privileged Blocks.
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
Note
See Appendix A: FilePermission Path Name Canonicalization Disabled By Default for
important information about a change in how FilePermission path names are
canonicalized.
Note
This list is not complete; other methods exist that require permissions. See the Java
SE and JDK API Specification for additional information on methods that throw
SecurityException and the permissions that are required.
SecurityManager Method column is allowed by the policy currently in effect. For example,
consider the following table row:
This table row specifies that a call to the getSystemEventQueue method in the
[Link] class results in a call to the checkPermission SecurityManager
method, which can only be successful if the following permission is granted to code on the call
stack:
[Link] "accessEventQueue";
The table rows have the following format, where the runtime value of foo replaces the string
{foo} in the permission name.
If the FileInputStream method (in this case, a constructor) is called with "/test/
MyTestFile" as the name argument, as in
FileInputStream("/test/MyTestFile");
then in order for the call to succeed, the following permission must be set in the current policy,
allowing read access to the file "/test/MyTestFile":
More specifically, the permission must either be explicitly set, as in this example, or implied by
another permission, such as the following:
In some cases, a term in braces is not exactly the same as the name of a specific method
argument but is meant to represent the relevant value. Here is an example:
Here, the appropriate host and port values are calculated by the receive method and passed
to checkAccept.
In most cases, just the name of the SecurityManager method called is listed. Where the
method is one of multiple methods of the same name, the argument types are also listed, for
example for checkRead(String) and checkRead(FileDescriptor). In other cases where
arguments may be relevant, they are also listed.
The following table is ordered by package name; the methods in classes in the [Link]
package are listed first, followed by methods in classes in the [Link] package, and so on:
checkPermission [Link]
[Link] "listenToAllAWTEvents"
public void addAWTEventListener(
AWTEventListener listener,
long eventMask)
public void removeAWTEventListener(
AWTEventListener listener)
checkPrintJobAc [Link]
[Link] cess "queuePrintJob"
public abstract PrintJob getPrintJob( Note: The getPrintJob method
Frame frame, String jobtitle, is actually abstract and thus can't
Properties props) invoke security checks. Each actual
implementation of the method
should call the
[Link]
r checkPrintJobAccess
method, which is successful only if
the
[Link]
"queuePrintJob" permission is
currently allowed.
checkPermission [Link]
[Link] "accessClipboard"
public abstract Clipboard Note: The
getSystemClipboard() getSystemClipboard method
is actually abstract and thus can't
invoke security checks. Each actual
implementation of the method
should call the
checkPermission method,
which is successful only if the
[Link]
"accessClipboard" permission
is currently allowed.
checkPermission [Link]
[Link] "accessEventQueue"
public final EventQueue
getSystemEventQueue()
[Link]
public static synchronized void
setBeanInfoSearchPath(String path[])
[Link]
public static void registerEditor(
Class targetType,
Class editorClass)
public static synchronized void
setEditorSearchPath(String path[])
checkDelete(Str [Link]
[Link] ing) "{name}", "delete"
public boolean delete()
public void deleteOnExit()
checkRead(FileD [Link]
[Link] escriptor) "readFileDescriptor"
FileInputStream(FileDescriptor fdObj)
[Link]
public boolean exists()
public boolean canRead()
public boolean isFile()
public boolean isDirectory()
public boolean isHidden()
public long lastModified()
public long length()
public String[] list()
public String[] list(
FilenameFilter filter)
public File[] listFiles()
public File[] listFiles(
FilenameFilter filter)
public File[] listFiles(
FileFilter filter)
[Link]
RandomAccessFile(String name, String mode)
RandomAccessFile(File file, String mode)
[Link]
public boolean canWrite()
public boolean createNewFile()
public static File createTempFile(
String prefix, String suffix)
public static File createTempFile(
String prefix,
String suffix,
File directory)
public boolean mkdir()
public boolean mkdirs()
public boolean renameTo(File dest)
public boolean setLastModified(long time)
public boolean setReadOnly()
checkPermission [Link]
[Link] on "enableSubstitution"
protected final boolean
enableResolveObject(boolean enable);
[Link]
protected final boolean
enableReplaceObject(boolean enable)
checkPermission [Link]
[Link] on
protected ObjectInputStream() "enableSubclassImplementatio
n"
[Link]
protected ObjectOutputStream()
checkRead(Strin [Link]
[Link] g) and "{name}", "read,write"
RandomAccessFile(String name, String checkWrite(Stri
mode) ng)
checkPermission [Link]
[Link] "getProtectionDomain"
public ProtectionDomain
getProtectionDomain()
checkCreateClas [Link]
[Link] sLoader "createClassLoader"
ClassLoader()
ClassLoader(ClassLoader parent)
checkPermission [Link]
"shutdownHooks"
[Link]
public void addShutdownHook(Thread hook)
public boolean removeShutdownHook(Thread
hook)
checkLink({libN [Link]
[Link] ame}) where "loadLibrary.{libName}"
public void load(String lib) {libName} is the lib,
public void loadLibrary(String lib) filename or libname
argument
[Link]
public static void load(String filename)
public static void loadLibrary(
String libname)
checkPermission [Link]
[Link] "setIO"
public static void setIn(InputStream in)
public static void setOut(PrintStream out)
public static void setErr(PrintStream err)
checkPermission [Link]
[Link] "{key}", "write"
public static String
setProperty(String key, String value)
checkPermission [Link]
[Link] "setSecurityManager"
public static synchronized void
setSecurityManager(SecurityManager s)
checkAccess({th [Link]
[Link] readGroup}) "modifyThreadGroup"
public static int
enumerate(Thread tarray[])
checkAccess({pa [Link]
[Link] rentThreadGroup "modifyThreadGroup"
Thread() })
Thread(Runnable target)
Thread(String name)
Thread(Runnable target, String name)
[Link]
ThreadGroup(String name)
ThreadGroup(
ThreadGroup parent,
String name)
checkAccess(thi Requires
[Link] s) [Link]
public final void interrupt() "modifyThreadGroup". Also
requires
[Link]
"modifyThread", since the
[Link]
interrupt() method is called
for each thread in the thread group
and in all of its subgroups. See the
Thread interrupt() method.
checkPermission [Link]
[Link] mission
public static void setAccessible(...) "suppressAccessChecks"
public void setAccessible(...)
checkPermission [Link]
[Link] "requestPasswordAuthenticati
public static PasswordAuthentication on"
requestPasswordAuthentication(
InetAddress addr,
int port,
String protocol,
String prompt,
String scheme)
checkMulticast( [Link]( m
[Link] InetAddress) [Link](),
public void "accept,connect")
joinGroup(InetAddress mcastaddr)
public void
leaveGroup(InetAddress mcastaddr)
checkMulticast(
[Link] [Link]()) if
public void send(DatagramPacket p) or ([Link]().isMulticas
checkConnect( p tAddress()) {
.getAddress().g
etHostAddress() [Link](
, [Link]())
([Link]()).getHostAd
dress(),
"accept,connect")
} else {
port = [Link]();
host =
[Link]().getHostAddr
ess();
if (port == -1)
[Link]
"{host}","resolve";
else
[Link]
"{host}:{port}","connect";
}
[Link]
"{host}","resolve";
else
[Link]
"{host}:{port}","connect"
}
checkConnect({h [Link]
[Link] ost}, -1) "{host}", "resolve"
public String getHostName()
public static InetAddress[]
getAllByName(String host)
public static InetAddress getLocalHost()
[Link]
public InetAddress getLocalAddress()
checkListen({po [Link]
[Link] rt}) "localhost:{port}","listen";
ServerSocket(...)
[Link]
DatagramSocket(...)
[Link]
MulticastSocket(...)
checkSetFactory [Link]
[Link] "setFactory"
public static synchronized void
setSocketFactory(...)
[Link]
public static synchronized void
setSocketImplFactory(...)
[Link]
public static synchronized void
setURLStreamHandlerFactory(...)
[Link]
public static synchronized void
setContentHandlerFactory(...)
public static void
setFileNameMap(FileNameMap map)
[Link]
public static void
setFollowRedirects(boolean set)
[Link]
public static synchronized
ActivationGroup createGroup(...)
public static synchronized void
setSystem(ActivationSystem system)
[Link]
public synchronized static void
setSocketFactory(...)
checkConnect({h [Link]
[Link] ost}, {port}) "{host}:{port}", "connect"
Socket(...)
checkAccept({ho [Link]
[Link] st}, {port}) "{host}:{port}", "accept"
public synchronized void
receive(DatagramPacket p)
checkCreateClas [Link]
[Link] sLoader "createClassLoader"
URLClassLoader(...)
checkPermission [Link]
[Link] sion
public AccessControlContext( "createAccessControlContext"
AccessControlContext acc,
DomainCombiner combiner)
public DomainCombiner getDomainCombiner()
checkSecurityAc [Link]
[Link] cess("addIdenti sion
public void addCertificate(...) tyCertificate") "addIdentityCertificate"
checkSecurityAc [Link]
[Link] cess("removeIde sion
public void removeCertificate(...) ntityCertificat "removeIdentityCertificate"
e")
checkSecurityAc [Link]
[Link] cess("setIdenti sion "setIdentityInfo"
public void setInfo(String info) tyInfo")
checkSecurityAc [Link]
[Link] cess("setIdenti sion "setIdentityPublicKey"
public void setPublicKey(PublicKey key) tyPublicKey")
checkSecurityAc [Link]
[Link] cess("printIden sion "printIdentity"
public String toString(...) tity")
checkSecurityAc [Link]
[Link] cess("setSystem sion "setSystemScope"
protected static void setSystemScope() Scope")
checkPermission [Link]
[Link] sion "setPolicy"
public static void
setPolicy(Policy policy)
checkPermission [Link]
[Link] sion "createPolicy.{type}"
public static Policy
getInstance(
String type,
SpiParameter params)
getInstance(
String type,
SpiParameter params,
String provider)
getInstance(
String type,
SpiParameter params,
Provider provider)
checkSecurityAc [Link]
[Link] cess("clearProv sion
public synchronized void clear() iderProperties. "clearProviderProperties.
"+{name}) {name}" where name is the
provider name.
checkSecurityAc [Link]
[Link] cess("putProvid sion "putProviderProperty.
public synchronized Object erProperty."+ {name}" where name is the
put(Object key, Object value) {name}) provider name.
checkSecurityAc [Link]
[Link] cess("removePro sion
public synchronized Object viderProperty." "removeProviderProperty.
remove(Object key) +{name}) {name}" where name is the
provider name.
checkCreateClas [Link]
[Link] sLoader "createClassLoader"
SecureClassLoader(...)
checkSecurityAc [Link]
[Link] cess("insertPro sion "insertProvider.{name}"
public static int vider."+provide
addProvider(Provider provider) [Link]())
public static int
insertProviderAt(
Provider provider,
int position);
checkSecurityAc [Link]
[Link] cess("removePro sion "removeProvider.{name}"
public static void vider."+name)
removeProvider(String name)
checkSecurityAc [Link]
cess("setProper sion "setProperty.{key}"
[Link] ty."+key)
public static void
setProperty(String key, String datum)
checkSecurityAc [Link]
[Link] cess("getSigner sion "getSignerPrivateKey"
public PrivateKey getPrivateKey() PrivateKey")
checkSecurityAc [Link]
[Link] cess("setSigner sion "setSignerKeypair"
public final void Keypair")
setKeyPair(KeyPair pair)
checkPermission [Link]
[Link] "setLog"
public static synchronized void
setLogWriter(PrintWriter out)
checkPermission [Link]
[Link] "setLog"
public static synchronized void
setLogStream(PrintWriter out)
checkRead [Link]
[Link] "{name}","read"
ZipFile(String name)
checkPermission [Link]
[Link] ission "getSubject"
public static Subject getSubject(
final AccessControlContext acc)
checkPermission [Link]
[Link] ission "setReadOnly"
public void setReadOnly()
checkPermission [Link]
[Link] ission "doAs"
public static Object doAs(
final Subject subject,
final PrivilegedAction action)
checkPermission [Link]
[Link] ission "doAs"
public static Object doAs(
final Subject subject,
final PrivilegedExceptionAction action)
throws
[Link]
checkPermission [Link]
[Link] ission "doAsPrivileged"
public static Object doAsPrivileged(
final Subject subject,
final PrivilegedAction action,
final AccessControlContext acc)
[Link]
checkPermission [Link]
[Link] ission
public Subject getSubject() "getSubjectFromDomainCombine
r"
checkPermission [Link]
ission
[Link] "getSubjectFromDomainCombine
public Subject getSubject() r"
checkPermission [Link]
ission "createLoginContext.
[Link] {name}"
public LoginContext(String name)
throws LoginException
checkPermission [Link]
[Link] ission "createLoginContext.
public LoginContext( {name}"
String name,
Subject subject)
throws LoginException
checkPermission [Link]
[Link] ission "createLoginContext.
public LoginContext( {name}"
String name,
CallbackHandler callbackHandler)
throws LoginException
checkPermission [Link]
[Link] ission
public static Configuration "getLoginConfiguration"
getConfiguration()
checkPermission [Link]
[Link] ission
public static void setConfiguration( "setLoginConfiguration"
Configuration configuration)
checkPermission [Link]
[Link] ission
public static void refresh() "refreshLoginConfiguration"
checkPermission [Link]
[Link] ission
public static Configuration "createLoginConfiguration.
getInstance( {type}"
String type,
SpiParameter params)
getInstance(
String type,
SpiParameter params,
String provider)
getInstance(String type,
SpiParameter params,
Provider provider)
Each of the specified check methods calls the SecurityManager checkPermission method with
the specified permission, except for the checkConnect and checkRead methods that take a
context argument. Those methods expect the context to be an AccessControlContext and
they call the context's checkPermission method with the specified permission.
Method Permission
Note
This method is deprecated; use
instead public void
checkPermission(Permi
ssion perm);
Method Permission
if cmd is an absolute path:
public void checkExec(String cmd);
[Link] "{cmd}", "execute";
else
[Link] "<<ALL_FILES>>",
"execute";
Method Permission
Note
This method is deprecated; use
instead public void
checkPermission(Permi
ssion perm);
Method Permission
Note
This method is deprecated; use
instead public void
checkPermission(Permi
ssion perm);
Note
This method is deprecated; use
instead public void
checkPermission(Permi
ssion perm);
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
The source location for the policy information utilized by the Policy object is up to the Policy
implementation. The Policy reference implementation obtains its information from static policy
configuration files.
The rest of this document pertains to the Policy reference implementation and the syntax that
must be used in policy files it reads:
• Default Policy Implementation
• Default Policy File Locations
• Modifying the Policy Implementation
• Policy File Syntax
• Policy File Examples
• Property Expansion in Policy Files
• Windows Systems, File Paths, and Property Expansion
• General Expansion in Policy Files
There is by default a single system-wide policy file, and a single (optional) user policy file. By
default, permissions required by JDK modules that are loaded by the platform class loader or
its ancestors are always granted.
The Policy reference implementation is initialized the first time its getPermissions method is
called, or whenever its refresh method is called. Initialization involves parsing the policy
configuration file(s) (see Policy File Syntax), and then populating the Policy object.
The system policy file is meant to grant system-wide code permissions. The [Link] file
installed with the JDK allows anyone to listen on dynamic ports, and allows any code to read
certain "standard" properties that are not security-sensitive, such as the [Link] and
[Link] properties.
The policy file locations are specified as the values of properties whose names are of the
following form:
[Link].n
Here, n is a number. You specify each such property value in a line of the following form:
[Link].n=URL
Here, URL is a URL specification. For example, the default system and user policy files are
defined in the security properties file as:
[Link].1=file:${[Link]}/conf/security/[Link]
[Link].2=file:${[Link]}/.[Link]
(See Property Expansion in Policy Files for information about specifying property values via a
special syntax, such as specifying the [Link] property value via ${[Link]}.)
You can actually specify a number of URLs (including ones of the form "[Link] and all the
designated policy files will get loaded. You can also comment out or change the second one to
disable reading the default user policy file.
The algorithm starts at [Link].1, and keeps incrementing until it does not find a URL.
Thus if you have [Link].1 and [Link].3, and [Link].3 will never be read.
The URL can be any regular URL or simply the name of a policy file in the current directory, as
in:
The -[Link] option ensures that the default security manager is installed,
and thus the application is subject to policy checks. It is not required if the application SomeApp
installs a security manager.
If you use the following command (note the double equals) then just the specified policy file will
be used; all the ones indicated in the security properties file will be ignored.
Note
The policy file value of the -[Link] option is ignored if the
[Link] property in the security properties file is set to false.
The default is true.
An alternative policy class can be given to replace the Policy reference implementation class,
as long as the former is a subclass of the abstract Policy class and implements the
getPermissions method (and other methods as necessary).
One of the types of properties you can set in [Link] is of the following form:
[Link]=PolicyClassName
PolicyClassName must specify the fully qualified name of the desired Policy implementation
class.
The default security properties file entry for this property is the following:
[Link]=[Link]
To customize, you can change the property value to specify another class, as in
[Link]=[Link]
Keystore Entry
A keystore is a database of private keys and their associated digital certificates such as X.509
certificate chains authenticating the corresponding public keys. The keytool utility is used to
create and administer keystores. The keystore specified in a policy configuration file is used to
look up the public keys of the signers specified in the grant entries of the file. A keystore entry
must appear in a policy configuration file if any grant entries specify signer aliases, or if any
grant entries specify principal aliases.
At this time, there can be only one keystore/keystorePasswordURL entry in the policy file
(other entries following the first one are ignored). This entry can appear anywhere outside the
file's grant entries. It has the following syntax:
Here,
some_keystore_url
Specifies the URL location of the keystore.
some_password_url
Specifies the URL location of the keystore password.
keystore_type
Specifies the keystore type.
keystore_provider
Specifies the keystore provider.
Note
• The input stream from some_keystore_url is passed to the [Link]
method.
• If NONE is specified as the URL, then a null stream is passed to the
[Link] method. NONE should be specified in the URL if the KeyStore
is not file-based. For example, if it resides on a hardware token device.
• The URL is relative to the policy file location. If the policy file is specified in the
security properties file as:
[Link].1=[Link]
keystore ".keystore";
[Link]
A keystore type defines the storage and data format of the keystore information, and the
algorithms used to protect private keys in the keystore and the integrity of the keystore itself.
The default type is "PKCS12". Thus, if the keystore type is "PKCS12", it does not need to be
specified in the keystore entry.
Grant Entries
Code being executed is always considered to come from a particular "code source"
(represented by an object of type CodeSource). The code source includes not only the location
(URL) where the code originated from, but also a reference to the certificate(s) containing the
public key(s) corresponding to the private key(s) used to sign the code. Certificates in a code
source are referenced by symbolic alias names from the user's keystore. Code is also
considered to be executed as a particular principal (represented by an object of type
Principal), or group of principals.
Each grant entry includes one or more "permission entries" preceded by optional codeBase,
signedBy, and principal name/value pairs that specify which code you want to grant the
permissions. The basic format of a grant entry is the following:
All non-italicized items must appear as-is (although case doesn't matter and some are
optional). Italicized items represent variable values.
A grant entry must begin with the word grant.
signedBy Value
A signedBy value indicates the alias for a certificate stored in the keystore. The public key
within that certificate is used to verify the digital signature on the code; you grant the
permission(s) to code signed by the private key corresponding to the public key in the keystore
entry specified by the alias.
The signedBy value can be a comma-separated list of multiple aliases. An example is
"Adam,Eve,Charles", which means "signed by Adam and Eve and Charles"; the relationship is
AND, not OR. To be more exact, a statement like "Code signed by Adam" means "Code in a
class file contained in a JAR which is signed using the private key corresponding to the public
key certificate in the keystore whose entry is aliased by Adam".
The signedBy field is optional in that, if it is omitted, it signifies "any signer". It doesn't matter
whether the code is signed or not or by whom.
principal Value
A principal value specifies a class_name/principal_name pair which must be present within the
executing thread's principal set. The principal set is associated with the executing code by way
of a Subject.
The principal_class_name may be set to the wildcard value, *, which allows it to match any
Principal class. In addition, the principal_name may also be set to the wildcard value, *,
allowing it to match any Principal name. When setting the principal_class_name or
principal_name to *, do not surround the * with quotes. Also, if you specify a wildcard principal
class, you must also specify a wildcard principal name.
The principal field is optional in that, if it is omitted, it signifies "any principals".
codeBase Value
A codeBase value indicates the code source location; you grant the permission(s) to code from
that location. An empty codeBase entry signifies "any code"; it doesn't matter where the code
originates from.
Note
A codeBase value is a URL and thus should always utilize slashes (never backslashes)
as the directory separator, even when the code source is actually on a Windows
system. Thus, if the source location for code on a Windows system is actually
C:\somepath\api\, then the policy codeBase entry should look like:
The exact meaning of a codeBase value depends on the characters at the end. A codeBase with
a trailing "/" matches all class files (not JAR files) in the specified directory. A codeBase with a
trailing "/*" matches all files (both class and JAR files) contained in that directory. A codeBase
with a trailing "/-" matches all files (both class and JAR files) in the directory and recursively
all files in subdirectories contained in that directory. The following table illustrates the different
cases:
Table 1-7 How Codebase URLs in Downloaded Code Match Those in Policy Files
If you are using a modular runtime image (see the jlink tool), you can grant permissions to
the application and library modules in the image by specifying a jrt URL as the codeBase
value in a policy file. See JEP 220: Modular Run-Time Images for more information about jrt
URLs.
The following example grants permission to read the foo property to the module
[Link]:
The "action" is required for many permission types, such as [Link] (where it
specifies what type of file access is permitted). It is not required for categories such as
[Link] where it is not necessary, you either have the permission
specified by the "target_name" value following the permission_class_name or you don't.
The signedBy name/value pair for a permission entry is optional. If present, it indicates a
signed permission. That is, the permission class itself must be signed by the given alias(es) in
order for the permission to be granted. For example, suppose you have the following grant
entry:
grant {
permission Foo "foobar", signedBy "FooSoft";
};
Then this permission of type Foo is granted if the [Link] permission was placed in a JAR
file and the JAR file was signed by the private key corresponding to the public key in the
certificate specified by the "FooSoft" alias, or if [Link] is a system class, since system
classes are not subject to policy restrictions.
Items that appear in a permission entry must appear in the specified order (permission,
permission_class_name, "target_name", "action", and signedBy "signer_names"). An entry is
terminated with a semicolon.
Case is unimportant for the identifiers (permission, signedBy, codeBase, etc.) but is significant
for the permission_class_name or for any string that is passed in as a value.
Note
See Appendix A: FilePermission Path Name Canonicalization Disabled By Default for
important information about a change in how FilePermission path names are
canonicalized.
grant {
permission [Link] "C:\\users\\cathy\\[Link]", "read";
};
The reason this is necessary is because the strings are processed by a tokenizer
([Link]), which allows "\" to be used as an escape string (for example, "\n"
to indicate a new line) and which thus requires two backslashes to indicate a single backslash.
After the tokenizer has processed the previous file path string, converting double backslashes
to single backslashes, the end result is
"C:\users\cathy\[Link]"
The following policy configuration file specifies that only code that satisfies the following
conditions can call methods in the Security class to add or remove providers or to set
Security Properties:
• The code was loaded from a signed JAR file that is in the "/home/sysadmin/" directory on
the local file system.
• The signature can be verified using the public key referenced by the alias name "sysadmin"
in the keystore.
If this policy is in effect, then code that comes in a JAR file signed by "sysadmin" can add/
remove providers, regardless of where the JAR file originated from.
The following is a policy configuration file without a signer:
In this case, code that comes from anywhere in the "home/sysadmin/" directory on the local
file system can add/remove providers. The code does not need to be signed.
The following is a policy configuration file where neither codeBase nor signedBy is included:
grant {
permission [Link] "[Link].*";
permission [Link] "[Link].*";
};
Here, with both code source components missing, any code (regardless of where it originated
from, or whether or not it is signed, or who signed it) can add/remove providers.
The following represents a principal-based entry:
This permits any code executing as the X500Principal, "cn=Alice", permission to read and
write to "/home/Alice”.
This permits any code executing as an X500Principal (regardless of the distinguished name),
permission to read and write to "/tmp”.
The following example shows a grant statement with both codesource and principal
information:
This allows code downloaded from "[Link]", signed by "Duke", and executed
by "cn=Alice", permission to read and write into the "/tmp/games" directory.
The following example shows a grant statement with KeyStore alias replacement:
keystore "[Link]
[Link].x500.X500Principal "cn=Alice"
This assumes that X.509 certificate associated with the keystore alias, alice, has a subject
distinguished name of "cn=Alice". This allows code executed by the X500Principal "cn=Alice"
permission to read and write into the "/tmp/games" directory.
${[Link]}
appears in a policy file, or in the security properties file, it will be expanded to the value of the
system property. For example,
will expand "${[Link]}" to use the value of the "[Link]" system property. If that
property's value is "/home/cathy", then the previous example is equivalent to
In order to assist in platform-independent policy files, you can also use the special notation of
"${/}", which is a shortcut for ${[Link]}". This allows things like
If the value of the "[Link] " property is /home/cathy, and you are on Linux or macOS, the
previous example gets converted to:
If on the other hand the "[Link]" value is C:\users\cathy and you are on a Windows
system, the previous example gets converted to:
then any file separator characters will be automatically converted to / characters. For example,
suppose the value of [Link] is C:\Users\me\lib. Thus on a Windows system, the
previous example would get converted to
Thus you don't need to use ${/} in codebase strings (and you shouldn't). Property expansion
takes place anywhere a double quoted string is allowed in the policy file. This includes the
"signer_names", "URL", "target_name", and "action" fields. Whether or not property expansion
is allowed is controlled by the value of the "[Link]" property in the security
properties file. If the value of this property is true (the default), expansion is allowed.
Note
You can't use nested properties; they will not work. For example,
"${user.${foo}}"
doesn't work, even if the "foo" property is set to "home". The reason is the property
parser doesn't recognize nested properties; it simply looks for the first "${", and then
keeps looking until it finds the first "}" and tries to interpret the result (in this case, "$
{user.$foo}") as a property, but fails if there is no such property.
Note
If a property can't be expanded in a grant entry, permission entry, or keystore entry,
that entry is ignored. For example, if the system property "foo" is not defined and you
have:
then all the permissions in this grant entry are ignored. If you have
grant {
permission Foo "${foo}";
permission Bar "barTarget";
};
then only the "permission Foo..." entry is ignored. And finally, if you have
keystore "${foo}";
grant {
permission [Link] "C:\\users\\cathy\\[Link]", "read";
};
"C:\users\cathy\[Link]"
Expansion of a property in a string takes place after the tokenizer has processed the string.
Thus if you have the string
"${[Link]}\\[Link]"
then first the tokenizer processes the string, converting the double backslashes to a single
backslash, and the result is
"${[Link]}\[Link]"
"C:\users\cathy\[Link]"
"${[Link]}${/}[Link]"
${{protocol:protocol_data}}
If such a string occurs in a permission name, then the value in protocol determines the exact
type of expansion that should occur, and protocol_data is used to help perform the expansion.
protocol_data may be empty, in which case the previous string should simply take the form:
${{protocol}}
There are two protocols supported in the default policy file implementation:
1. ${{self}}
The protocol, self, denotes a replacement of the entire string, ${{self}}, with one or
more principal class/name pairs. The exact replacement performed depends upon the
contents of the grant clause to which the permission belongs.
If the grant clause does not contain any principal information, the permission will be
ignored (permissions containing ${{self}} in their target names are only valid in the
context of a principal-based grant clause). For example, BarPermission will always be
ignored in the following grant clause:
If the grant clause contains principal information, ${{self}} will be replaced with that
same principal information. For example, ${{self}} in BarPermission will be replaced with
[Link].x500.X500Principal "cn=Duke" in the following grant clause:
If there is a comma-separated list of principals in the grant clause, then ${{self}} will be
replaced by the same comma-separated list or principals. In the case where both the
principal class and name are wildcarded in the grant clause, ${{self}} is replaced with all
the principals associated with the Subject in the current AccessControlContext.
The following example describes a scenario involving both self and Keystore Alias
Replacement together:
keystore "[Link]
keystore "[Link]
In the previous example the X.509 certificate associated with the alias, duke, is retrieved
from the KeyStore, [Link]/blah/.keystore. Assuming duke's certificate specifies
"o=dukeOrg, cn=duke" as the subject distinguished name, then ${{alias:duke}} is
replaced with [Link].x500.X500Principal "o=dukeOrg, cn=duke".
The permission entry is ignored under the following error conditions:
• The keystore entry is unspecified
• The alias_name is not provided
• The certificate for alias_name can not be retrieved
• The certificate retrieved is not an X.509 certificate
Before JDK 9, path names were canonicalized when two FilePermission objects were
compared. This allowed a program to access a file using a different name than the name that
was granted to a FilePermission object in a policy file, as long as the object pointed to the
same file. Because the canonicalization had to access the underlying file system, it could be
quite slow.
In JDK 9, path name canonicalization is disabled by default. This means two FilePermission
objects aren’t equal to each other if one uses an absolute path and the other uses a relative
path, or one uses a symbolic link and the other uses a target, or one uses a Windows long
name and the other uses a DOS-style 8.3 name. This is true even if they all point to the same
file in the file system.
Therefore, if a path name is granted to a FilePermission object in a policy file, then the
program should also access that file using the same path name style. For example, if the path
name in the policy file is using a symbolic link, then the program should also use that symbolic
link. Accessing the file with the target path name will fail the permission check.
Compatibility Layer
A compatibility layer has been added to ensure that granting a FilePermission object for a
relative path will permit applications to access the file with an absolute path (and conversely).
This works for the default Policy provider and the Limited doPrivileged calls.
For example, a FilePermission object on a file with a relative path name of "a" no longer
implies a FilePermission object on the same file with an absolute path name as "/pwd/a"
("pwd" is the current working directory). Granting code a FilePermission object to read "a"
allows that code to also read "/pwd/a" when a Security Manager is enabled.
The compatibility layer doesn’t cover translations between symbolic links and targets, or
Windows long names and DOS-style 8.3 names, or any other different name forms that can be
canonicalized to the same name.
Troubleshooting Security
To monitor security access, you can set the [Link] system property, which
determines what trace messages are printed during execution. To view security properties,
security providers, and TLS-related settings, specify the -XshowSettings:security option in
the java command.
Topics
• The [Link] System Property
• Printing Thread and Timestamp Information
• The java -XshowSettings:security Option
Note
• To use more than one option, separate options with a comma.
• JSSE also provides dynamic debug tracing support for SSL/TLS/DTLS
troubleshooting. See Debugging Utilities.
The following table lists [Link] options and links to further information about
each option:
Note
Use the
System
property
[Link].m
axSignatu
reFileSiz
e to specify
the
maximum
size, in
bytes, of
signature
files in a
signed JAR.
Its default
value is
16000000
(16 MB).
Notes on Terminology
• Prior to JDK 1.4, the JCE was an unbundled product, and as such, the JCA and JCE were
regularly referred to as separate, distinct components. As JCE is now bundled in the JDK,
the distinction is becoming less apparent. Since the JCE uses the same architecture as the
JCA, the JCE should be more properly thought of as a part of the JCA.
Warning
The JCA makes it easy to incorporate security features into your application. However,
this document does not cover the theory of security/cryptography beyond an
elementary introduction to concepts necessary to discuss the APIs. This document
also does not cover the strengths/weaknesses of specific algorithms, not does it cover
protocol design. Cryptography is an advanced topic and one should consult a solid,
preferably recent, reference in order to make best use of these tools.
You should always understand what you are doing and why: DO NOT simply copy
random code and expect it to fully solve your usage scenario. Many applications have
been deployed that contain significant security or performance problems because the
wrong tool or algorithm was selected.
Implementation interoperability means that various implementations can work with each other,
use each other's keys, or verify each other's signatures. This would mean, for example, that for
the same algorithms, a key generated by one provider would be usable by another, and a
signature generated by one provider would be verifiable by another.
Algorithm extensibility means that new algorithms that fit in one of the supported engine
classes can be added easily.
Provider Architecture
Providers contain a package (or a set of packages) that supply concrete implementations for
the advertised cryptographic algorithms.
md = [Link]("SHA-256");
Alternatively, the program can request the objects from a specific provider. Each provider has a
name used to refer to it. For example, the following statement requests a SHA-256 message
digest from the provider named ProviderC:
md = [Link]("SHA-256", "ProviderC");
The following figures illustrates requesting an SHA-256 message digest implementation. They
show three different providers that implement various message digest algorithms (SHA-256,
SHA-384, and SHA-512). The providers are ordered by preference from left to right (1-3). In
Figure 2-1, an application requests a SHA-256 algorithm implementation without specifying a
provider name. The providers are searched in preference order and the implementation from
the first provider supplying that particular algorithm, ProviderB, is returned. In Figure 2-2, the
application requests the SHA-256 algorithm implementation from a specific provider,
ProviderC. This time, the implementation from ProviderC is returned, even though a provider
with a higher preference order, ProviderB, also supplies an SHA-256 implementation.
Cryptographic implementations in the JDK are distributed via several different providers (Sun,
SunJSSE, SunJCE, SunRsaSign) primarily for historical reasons, but to a lesser extent by the type
of functionality and algorithms they provide. Other Java runtime environments may not
necessarily contain these providers, so applications should not request a provider-specific
implementation unless it is known that a particular provider will be available.
The JCA offers a set of APIs that allow users to query which providers are installed and what
services they support.
This architecture also makes it easy for end-users to add additional providers. Many third party
provider implementations are already available. See The Provider Class for more information
on how providers are written, installed, and registered.
Cipher c = [Link]("AES");
[Link](ENCRYPT_MODE, key);
Here an application wants an "AES" [Link] instance, and doesn't care which
provider is used. The application calls the getInstance() factory methods of the Cipher
engine class, which in turn asks the JCA framework to find the first provider instance that
supports "AES". The framework consults each installed provider, and obtains the provider's
instance of the Provider class. (Recall that the Provider class is a database of available
algorithms.) The framework searches each provider, finally finding a suitable entry in CSP3.
This database entry points to the implementation class [Link] which extends
CipherSpi, and is thus suitable for use by the Cipher engine class. An instance of
[Link] is created, and is encapsulated in a newly-created instance of
[Link], which is returned to the application. When the application now does the
init() operation on the Cipher instance, the Cipher engine class routes the request into the
corresponding engineInit() backing method in the [Link] class.
Java Security Standard Algorithm Names lists the Standard Names defined for the Java
environment. Other third-party providers may define their own implementations of these
services, or even additional services.
Keystores
A database called a "keystore" can be used to manage a repository of keys and certificates.
Keystores are available to applications that need data for authentication, encryption, or signing
purposes.
Applications can access a keystore via an implementation of the KeyStore class, which is in
the [Link] package. As of JDK 9, the default and recommended keystore type
(format) is "pkcs12", which is based on the RSA PKCS12 Personal Information Exchange
Syntax Standard. Previously, the default keystore type was "jks", which is a proprietary format.
Other keystore formats are available, such as "jceks", which is an alternate proprietary
keystore format, and "pkcs11", which is based on the RSA PKCS11 Standard and supports
access to cryptographic tokens such as hardware security modules and smartcards.
Applications can choose different keystore implementations from different providers, using the
same provider mechanism described previously. See Key Management.
Note
A generator creates objects with brand-new contents, whereas a factory creates
objects from existing material (for example, an encoding).
Note
See CertPathBuilder, CertPathValidator, and CertStoreengine classes in the Java
PKI Programmer's Guide.
The guide will cover the most useful high-level classes first (Provider, Security,
SecureRandom, MessageDigest, Signature, Cipher, and Mac), then delve into the various
support classes. For now, it is sufficient to simply say that Keys (public, private, and secret) are
generated and represented by the various JCA classes, and are used by the high-level classes
as part of their operation.
This section shows the signatures of the main methods in each class and interface. Examples
for some of these classes (MessageDigest, Signature, KeyPairGenerator, SecureRandom,
KeyFactory, and key specification classes) are supplied in the corresponding Code Examples
sections.
The complete reference documentation for the relevant Security API packages can be found in
the package summaries:
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
There are several types of services that can be implemented by provider packages; See
Engine Classes and Algorithms.
The different implementations may have different characteristics. Some may be software-
based, while others may be hardware-based. Some may be platform-independent, while others
may be platform-specific. Some provider source code may be available for review and
evaluation, while some may not. The JCA lets both end-users and developers decide what
their needs are.
You can find information about how end-users install the cryptography implementations that fit
their needs, and how developers request the implementations that fit theirs.
Note
To implement a provider, see Steps to Implement and Integrate a Provider.
where
EngineClassName
is the desired engine type (for example, Signature, MessageDigest, or Cipher). For
example:
Note
The algorithm name is not case-sensitive. For example, all the following calls are
equivalent:
[Link]("SHA256withRSA")
[Link]("sha256withrsa")
[Link]("Sha256WithRsa")
any given Java Virtual Machine (JVM), providers are installed in a given preference order, the
order in which the provider list is searched if a specific provider is not requested. (See
Installing Providers.) For example, suppose there are two providers installed in a JVM,
PROVIDER_1 and PROVIDER_2. Assume that:
A federal agency program would then have the following call, specifying PROVIDER_2 since it
has the certified implementation:
Note
General purpose applications SHOULD NOT request cryptographic services from
specific providers. Otherwise, applications are tied to specific providers which may not
be available on other Java implementations. They also might not be able to take
advantage of available optimized providers (for example hardware accelerators via
PKCS11 or native OS implementations such as Microsoft's MSCAPI) that have a
higher preference order than the specific requested provider.
Installing Providers
In order to be used, a cryptographic provider must first be installed, then registered either
statically or dynamically. There are a variety of Sun providers shipped with this release (SUN,
SunJCE, SunJSSE, SunRsaSign, etc.) that are already installed and registered. The following
sections describe how to install and register additional providers.
All JDK providers are already installed and registered. However, if you require any third-party
providers, see Step 8: Prepare for Testing from Steps to Implement and Integrate a Provider
for information about how to add providers to the class or module path, register providers
(statically or dynamically), and add any required permissions.
This configuration file specifies that code loaded from a signed JAR file in the /home/
sysadmin/ directory on the local file system can add or remove providers or set provider
properties. (Note that the signature of the JAR file can be verified using the public key
referenced by the alias name sysadmin in the user's keystore.).
Either component of the code source (or both) may be missing. Here's an example of a
configuration file where the codeBase is omitted:
If this policy is in effect, code that comes in a JAR File signed by /home/sysadmin/ directory on
the local filesystem can add or remove providers. The code does not need to be signed.
An example where neither codeBase nor signedBy is included is:
grant {
permission [Link] "insertProvider.*";
permission [Link] "removeProvider.*";
};
Here, with both code source components missing, any code (regardless of where it originates,
or whether or not it is signed, or who signed it) can add/remove providers. Obviously, this is
definitely not recommended, as this grant could open a security hole. Untrusted code could
install a Provider, thus affecting later code that is depending on a properly functioning
implementation. (For example, a rogue Cipher object might capture and store the sensitive
information it receives.)
Managing Providers
The following tables summarize the methods in the Security class you can use to query which
Providers are installed, as well as to install or remove providers at runtime.
Querying Providers
Method Description
static Provider[] getProviders() Returns an array containing all the installed
providers (technically, the Provider subclass for
each package provider). The order of the
Providers in the array is their preference order.
static Provider getProvider (String Returns the Provider named providerName. It
providerName) returns null if the Provider is not found.
Adding Providers
Method Description
static int addProvider(Provider Adds a Provider to the end of the list of installed
provider) Providers. It returns the preference position in
which the Provider was added, or -1 if the
Provider was not added because it was already
installed.
Method Description
static int insertProviderAt (Provider Adds a new Provider at a specified position. If the
provider, int position) given provider is installed at the requested position,
the provider formerly at that position and all
providers with a position greater than position
are shifted up one position (towards the end of the
list). This method returns the preference position in
which the Provider was added, or -1 if the
Provider was not added because it was already
installed.
Removing Providers
Method Description
static void removeProvider(String name) Removes the Provider with the specified name. It
returns silently if the provider is not installed. When
the specified provider is removed, all providers
located at a position greater than where the
specified provider was are shifted down one
position (towards the head of the list of installed
providers).
Note
If you want to change the preference position of a provider, you must first remove it,
and then insert it back in at the new preference position.
Security Properties
The Security class maintains a list of system-wide Security Properties. These properties are
similar to the System properties, but are security-related. These properties can be set statically
(through the <java-home>/conf/security/[Link] file) or dynamically (using an
API). See Step 8.1: Configure the Provider from Steps to Implement and Integrate a Provider.
for an example of registering a provider statically with the [Link].n Security
Property. If you want to set properties dynamically, trusted programs can use the following
methods:
Note
The list of security providers is established during VM startup; therefore, the methods
described previously must be used to alter the provider list.
You must call setSeed before the first nextBytes call to prevent any environmental
randomness.
The randomness of the bits produced by the SecureRandom object depends on the
randomness of the seed bits
At any time a SecureRandom object may be re-seeded using one of the setSeed or reseed
methods. The given seed for setSeed supplements, rather than replaces, the existing seed;
therefore, repeated calls are guaranteed never to reduce randomness.
For example, the SHA-256 algorithm produces a 32-byte digest, and SHA-512's is 64 bytes.
A digest has two properties:
• It should be computationally infeasible to find two messages that hash to the same value.
• The digest should not reveal anything about the input that was used to generate it.
Message digests are used to produce unique and reliable identifiers of data. They are
sometimes called "checksums" or the "digital fingerprints" of the data. Changes to just one bit
of the message should produce a different digest value.
Message digests have many uses and can determine when data has been modified,
intentionally or not. When selecting a digest algorithm, one should always consult a recent
reference to determine its status and appropriateness for the task at hand.
• To compute a digest, create a message digest instance. The MessageDigest objects are
obtained by using one of the getInstance() methods in the MessageDigest class. See
How Provider Implementations Are Requested and Supplied.
The factory method returns an initialized message digest object. It thus does not need
further initialization.
The data chunks have to be supplied by calls to update method. See Updating a Message
Digest Object.
• The digest is computed using a call to one of the digest methods:
byte[] digest()
byte[] digest(byte[] input)
int digest(byte[] buf, int offset, int len)
and a private key and generates a relatively short (often fixed-size) string of bytes, called the
signature, with the following properties:
• Only the owner of a private/public key pair is able to create a signature. It should be
computationally infeasible for anyone having only the public key and a number of
signatures to recover the private key.
• Given the public key corresponding to the private key used to generate the signature, it
should be possible to verify the authenticity and integrity of the input.
A Signature object is initialized for signing with a Private Key and is given the data to be
signed. The resulting signature bytes are typically kept with the signed data. When verification
is needed, another Signature object is created and initialized for verification and given the
corresponding Public Key. The data and the signature bytes are fed to the signature object,
and if the data and signature match, the Signature object reports success.
Even though a signature seems similar to a message digest, they have very different purposes
in the type of protection they provide. In fact, algorithms such as "SHA256WithRSA" use the
message digest "SHA256" to initially "compress" the large data sets into a more manageable
form, then sign the resulting 32 byte message digest with the "RSA" algorithm.
For an example for signing and verifying data, see Generating and Verifying a Signature Using
Generated Keys.
• UNINITIALIZED
• SIGN
• VERIFY
When it is first created, a Signature object is in the UNINITIALIZED state. The Signature class
defines two initialization methods, initSign and initVerify, which change the state to SIGN
and VERIFY , respectively.
Signature objects are obtained by using one of the Signature getInstance() static factory
methods. See How Provider Implementations Are Requested and Supplied.
This method puts the Signature object in the SIGN state. If instead the Signature object is
going to be used for verification, it must first be initialized with the public key of the entity
whose signature is going to be verified. This initialization is done by calling either of these
methods:
Calls to the update method(s) should be made until all the data to be signed has been supplied
to the Signature object.
The first method returns the signature result in a byte array. The second stores the signature
result in the provided buffer outbuf, starting at offset. len is the number of bytes in outbuf
allotted for the signature. The method returns the number of bytes actually stored.
Signature encoding is algorithm specific. See Java Security Standard Algorithm Names to
know more about the use of ASN.1 encoding in the Java Cryptography Architecture.
A call to a sign method resets the signature object to the state it was in when previously
initialized for signing via a call to initSign. That is, the object is reset and available to
generate another signature with the same private key, if desired, via new calls to update and
sign.
Alternatively, a new call can be made to initSign specifying a different private key, or to
initVerify (to initialize the Signature object to verify a signature).
Calls to the update method(s) should be made until all the data to be verified has been
supplied to the Signature object. The signature can now be verified by calling one of the
verify methods:
The argument must be a byte array containing the signature. This byte array would hold the
signature bytes which were returned by a previous call to one of the sign methods.
The verify method returns a boolean indicating whether or not the encoded signature is the
authentic signature of the data supplied to the update method(s).
A call to the verify method resets the signature object to its state when it was initialized for
verification via a call to initVerify. That is, the object is reset and available to verify another
signature from the identity whose public key was specified in the call to initVerify.
Alternatively, a new call can be made to initVerify specifying a different public key (to
initialize the Signature object for verifying a signature from a different entity), or to initSign
(to initialize the Signature object for generating a signature).
Modes Of Operation
When encrypting using a simple block cipher, two identical blocks of plaintext will always
produce an identical block of cipher text. Cryptanalysts trying to break the ciphertext will have
an easier job if they note blocks of repeating text. A cipher mode of operation makes the
ciphertext less predictable with output block alterations based on block position or the values of
other ciphertext blocks. The first block will need an initial value, and this value is called the
initialization vector (IV). Since the IV simply alters the data before any encryption, the IV should
be random but does not necessarily need to be kept secret. There are a variety of modes, such
as CBC (Cipher Block Chaining), CFB (Cipher Feedback Mode), and OFB (Output Feedback
Mode). ECB (Electronic Codebook Mode) is a mode in which there is no influence from block
position or other ciphertext blocks. Because ECB ciphertexts are the same if they use the
same plaintext/key, this mode is not typically suitable for cryptographic applications and should
not be used.
Some algorithms such as AES and RSA allow for keys of different lengths, but others are fixed,
such as 3DES. Encryption using a longer key generally implies a stronger resistance to
message recovery. As usual, there is a trade off between security and time, so choose the key
length appropriately.
Most algorithms use binary keys. Most humans do not have the ability to remember long
sequences of binary numbers, even when represented in hexadecimal. Character passwords
are much easier to recall. Because character passwords are generally chosen from a small
number of characters (for example, [a-zA-Z0-9]), protocols such as "Password-Based
Encryption" (PBE) have been defined which take character passwords and generate strong
binary keys. In order to make the task of getting from password to key very time-consuming for
an attacker (via so-called "rainbow table attacks" or "precomputed dictionary attacks" where
common dictionary word->value mappings are precomputed), most PBE implementations will
mix in a random number, known as a salt, to reduce the usefulness of precomputed tables.
Newer cipher modes such as Authenticated Encryption with Associated Data (AEAD) (for
example, Galois/Counter Mode (GCM)) encrypt data and authenticate the resulting message
simultaneously. Additional Associated Data (AAD) can be used during the calculation of the
resulting AEAD tag (MAC), but this AAD data is not output as ciphertext. (For example, some
data might not need to be kept confidential, but should figure into the tag calculation to detect
modifications.) The [Link]() methods can be used to include AAD in the tag
calculations.
// MUST CHANGE IV VALUE if the same key were to be used again for encryption
"AES/CBC/PKCS5Padding"
"AES"
Cipher c1 = [Link]("AES/ECB/PKCS5Padding");
and
Cipher c1 = [Link]("AES");
Note
ECB mode is the easiest block cipher mode to use and is the default cipher mode.
ECB works well for single blocks of data and can be parallelized but generally should
not be used for encrypting multiple data blocks due to characteristics of the mode.
This could result in trivial and full disclosure of confidential data. While this mode is
available for use, it should only be used with an understanding of the cryptographic
risks involved.
Using modes such as CFB and OFB, block ciphers can encrypt data in units smaller than the
cipher's actual block size. When requesting such a mode, you may optionally specify the
number of bits to be processed at a time by appending this number to the mode name as
shown in the "AES/CFB8/NoPadding" and "AES/OFB32/PKCS5Padding" transformations. If no
such number is specified, a provider-specific default is used. (For example, the SunJCE provider
uses a default of 256 bits for AES.) Thus, block ciphers can be turned into byte-oriented
stream ciphers by using an 8 bit mode such as CFB8 or OFB8.
Java Security Standard Algorithm Names contains a list of standard names that can be used to
specify the algorithm name, mode, and padding scheme components of a transformation.
The objects returned by factory methods are uninitialized, and must be initialized before they
become usable.
ENCRYPT_MODE
Encryption of data.
DECRYPT_MODE
Decryption of data.
WRAP_MODE
Wrapping a [Link] into bytes so that the key can be securely transported.
UNWRAP_MODE
Unwrapping of a previously wrapped key into a [Link] object.
Each of the Cipher initialization methods takes an operational mode parameter (opmode), and
initializes the Cipher object for that mode. Other parameters include the key (key) or
certificate containing the key (certificate), algorithm parameters (params), and a source of
randomness (random).
If a Cipher object that requires parameters (for example, an initialization vector) is initialized
for encryption, and no parameters are supplied to the init method, the underlying cipher
implementation is supposed to supply the required parameters itself, either by generating
random parameters or by using a default, provider-specific set of parameters.
However, if a Cipher object that requires parameters is initialized for decryption, and no
parameters are supplied to the init method, an InvalidKeyException or
InvalidAlgorithmParameterException exception will be raised, depending on the init
method that has been used.
See Managing Algorithm Parameters.
The same parameters that were used for encryption must be used for decryption.
Note that when a Cipher object is initialized, it loses all previously-acquired state. In other
words, initializing a Cipher is equivalent to creating a new instance of that Cipher, and
initializing it. For example, if a Cipher is first initialized for decryption with a given key, and
then initialized for encryption, it will lose any state acquired while in decryption mode.
To encrypt or decrypt data in multiple steps, call one of the update methods:
A multiple-part operation must be terminated by one of the these doFinal methods (if there is
still some input data left for the last step), or by one of the following doFinal methods (if there
is no input data left for the last step):
All the doFinal methods take care of any necessary padding (or unpadding), if padding (or
unpadding) has been requested as part of the specified transformation.
A call to doFinal resets the Cipher object to the state it was in when initialized via a call to
init. That is, the Cipher object is reset and available to encrypt or decrypt (depending on the
operation mode that was specified in the call to init) more data.
If you are supplying the wrapped key bytes (the result of calling wrap) to someone else who will
unwrap them, be sure to also send additional information the recipient will need in order to do
the unwrap:
To unwrap the bytes returned by a previous call to wrap, first initialize a Cipher object for
UNWRAP_MODE, then call the following:
Here, wrappedKey is the bytes returned from the previous call to wrap, wrappedKeyAlgorithm is
the algorithm associated with the wrapped key, and wrappedKeyType is the type of the wrapped
key. This must be one of Cipher.SECRET_KEY, Cipher.PRIVATE_KEY, or Cipher.PUBLIC_KEY.
implementation itself, can be retrieved from the Cipher object by calling its getParameters
method, which returns the parameters as a [Link] object (or
null if no parameters are being used). If the parameter is an initialization vector (IV), it can
also be retrieved by calling the getIV method.
The same parameters that were used for encryption must be used for decryption. They can be
instantiated from their encoding and used to initialize the corresponding Cipher object for
decryption, see Example 2-4.
If you did not specify any parameters when you initialized a Cipher object, and you are not
sure whether or not the underlying implementation uses any parameters, you can find out by
simply calling the getParameters method of your Cipher object and checking the value
returned. A return value of null indicates that no parameters were used.
The following cipher algorithms implemented by the SunJCE provider use parameters:
• AES, DES-EDE, and Blowfish, when used in feedback (i.e., CBC, CFB, OFB, or PCBC)
mode, use an initialization vector (IV). The [Link] class
can be used to initialize a Cipher object with a given IV. In addition, CTR and GCM
modes require an IV.
• PBE Cipher algorithms use a set of parameters, comprising a salt and an iteration count.
The [Link] class can be used to initialize a Cipher
object implementing a PBE algorithm (for example: PBEWithHmacSHA256AndAES_256)
with a given salt and iteration count.
Note that you do not have to worry about storing or transferring any algorithm parameters for
use by the decryption operation if you use the SealedObject class. This class attaches the
parameters used for sealing (encryption) to the encrypted object contents, and uses the same
parameters for unsealing (decryption).
Example 2-3 Sample Code for Retrieving Parameters from the Cipher Object
The application can retrieve the generated parameters for encryption from the Cipher object
as follows:
Example 2-4 Sample Code for Initializing the Cipher Object for Decryption
The same parameters that were used for encryption must be used for decryption. They can be
instantiated from their encoding and used to initialize the corresponding Cipher object for
decryption as follows:
Topics
The Cipher Stream Classes
The SealedObject Class
return data that are read from the underlying InputStream but have additionally been
processed by the embedded Cipher object. The Cipher object must be fully initialized before
being used by a CipherInputStream.
For example, if the embedded Cipher has been initialized for decryption, the
CipherInputStream will attempt to decrypt the data it reads from the underlying
InputStream before returning them to the application.
This class adheres strictly to the semantics, especially the failure semantics, of its ancestor
classes [Link] and [Link]. This class has exactly those
methods specified in its ancestor classes, and overrides them all, so that the data are
additionally processed by the embedded cipher. Moreover, this class catches all exceptions
that are not thrown by its ancestor classes. In particular, the skip(long) method skips only
data that has been processed by the Cipher.
It is crucial for a programmer using this class not to use methods that are not defined or
overridden in this class (such as a new method or constructor that is later added to one of the
super classes), because the design and implementation of those methods are unlikely to have
considered security impact with regard to CipherInputStream. See Example 2-5 for its
usage, suppose cipher1 has been initialized for encryption. The program reads and encrypts
the content from the file /tmp/[Link] and then stores the result (the encrypted bytes) in /tmp/
[Link].
Example 2-6 demonstrates how to easily connect several instances of CipherInputStream and
FileInputStream. In this example, assume that cipher1 and cipher2 have been initialized for
encryption and decryption (with corresponding keys), respectively. The program copies the
content from file /tmp/[Link] to /tmp/[Link], except that the content is first encrypted and then
decrypted back when it is read from /tmp/[Link]. Of course since this program simply encrypts
text and decrypts it back right away, it's actually not very useful except as a simple way of
illustrating chaining of CipherInputStreams.
Note that the read methods of the CipherInputStream will block until data is returned from the
underlying cipher. If a block cipher is used, a full block of cipher text will have to be obtained
from the underlying InputStream.
cipher2 have been initialized for encryption and decryption (with corresponding keys),
respectively:
For example, if the embedded Cipher has been initialized for encryption, the
CipherOutputStream will encrypt its data, before writing them out to the underlying output
stream.
This class adheres strictly to the semantics, especially the failure semantics, of its ancestor
classes [Link] and [Link]. This class has exactly
those methods specified in its ancestor classes, and overrides them all, so that all data are
additionally processed by the embedded cipher. Moreover, this class catches all exceptions
that are not thrown by its ancestor classes.
It is crucial for a programmer using this class not to use methods that are not defined or
overridden in this class (such as a new method or constructor that is later added to one of the
super classes), because the design and implementation of those methods are unlikely to have
considered security impact with regard to CipherOutputStream.
See Example 2-7 , for its usage, suppose cipher1 has been initialized for encryption. The
program reads the content from the file /tmp/[Link], then encrypts and stores the result (the
encrypted bytes) in /tmp/[Link].
One thing to keep in mind when using block cipher algorithms is that a full block of plaintext
data must be given to the CipherOutputStream before the data will be encrypted and sent to
the underlying output stream.
There is one other important difference between the flush and close methods of this class,
which becomes even more relevant if the encapsulated Cipher object implements a block
cipher algorithm with padding turned on:
• flush flushes the underlying OutputStream by forcing any buffered output bytes that
have already been processed by the encapsulated Cipher object to be written out. Any
bytes buffered by the encapsulated Cipher object and waiting to be processed by it will
not be written out.
• close closes the underlying OutputStream and releases any system resources
associated with it. It invokes the doFinal method of the encapsulated Cipher object,
causing any bytes buffered by it to be processed and written out to the underlying stream
by calling its flush method.
Example 2-7 Sample Code for Using CipherOutputStream and FileOutputStream
CipherOutputStreamFileOutputStream
encrypt the serialized object contents. In this example, the String "This is a secret" is sealed
using the AES algorithm. Note that any algorithm parameters that may be used in the sealing
operation are stored inside of SealedObject:
// do the sealing
SealedObject so = new SealedObject("This is a secret", c);
The original object that was sealed can be recovered in two different ways:
• by using a Cipher object that has been initialized with the exact same algorithm, key,
padding scheme, etc., that were used to seal the object:
[Link](Cipher.DECRYPT_MODE, sKey);
try {
String s = (String)[Link](c);
} catch (Exception e) {
// do something
};
This approach has the advantage that the party who unseals the sealed object does not
require knowledge of the decryption key. For example, after one party has initialized the
cipher object with the required decryption key, it could hand over the cipher object to
another party who then unseals the sealed object.
• by using the appropriate decryption key (since AES is a symmetric encryption algorithm,
we use the same key for sealing and unsealing):
try {
String s = (String)[Link](sKey);
} catch (Exception e) {
// do something
};
In this approach, the getObject method creates a cipher object for the appropriate
decryption algorithm and initializes it with the given decryption key and the algorithm
parameters (if any) that were stored in the sealed object. This approach has the advantage
that the party who unseals the object does not need to keep track of the parameters (e.g.,
the IV) that were used to seal the object.
Only someone with the proper key will be able to verify the received message. Typically,
message authentication codes are used between two parties that share a secret key in order to
validate information transmitted between these parties.
You can initialize your Mac object with any (secret-)key object that implements the
[Link] interface. This could be an object returned by
[Link](), or one that is the result of a key
agreement protocol, as returned by [Link](),
or an instance of [Link].
With some MAC algorithms, the (secret-)key algorithm associated with the (secret-)key object
used to initialize the Mac object does not matter (this is the case with the HMAC-MD5 and
HMAC-SHA1 implementations of the SunJCE provider). With others, however, the (secret-)key
algorithm does matter, and an InvalidKeyException is thrown if a (secret-)key object with an
inappropriate (secret-)key algorithm is used.
Computing a MAC
A MAC can be computed in one step (single-part operation) or in multiple steps (multiple-part
operation). A multiple-part operation is useful if you do not know in advance how long the data
is going to be, or if the data is too long to be stored in memory all at once.
To compute the MAC of some data in a single step, call the following doFinal method:
To compute the MAC of some data in multiple steps, call one of the update methods:
A multiple-part operation must be terminated by the doFinal method (if there is still some input
data left for the last step), or by one of the following doFinal methods (if there is no input data
left for the last step):
Key Interfaces
The [Link] interface is the top-level interface for all opaque keys. It defines the
functionality shared by all opaque key objects.
To this point, we have focused the high-level uses of the JCA without getting lost in the details
of what keys are and how they are generated/represented. It is now time to turn our attention
to keys.
An opaque key representation is one in which you have no direct access to the key material
that constitutes a key. In other words: "opaque" gives you limited access to the key--just the
three methods defined by the Key interface: getAlgorithm, getFormat, and getEncoded.
This is in contrast to a transparent representation, in which you can access each key material
value individually, through one of the get methods defined in the corresponding KeySpec
interface (see The KeySpec Interface).
All opaque keys have three characteristics:
An Algorithm
The key algorithm for that key. The key algorithm is usually an encryption or asymmetric
operation algorithm (such as AES, DSA or RSA), which will work with those algorithms and with
related algorithms (such as SHA256withRSA). The name of the algorithm of a key is obtained
using this method:
String getAlgorithm()
An Encoded Form
The external encoded form for the key used when a standard representation of the key is
needed outside the Java Virtual Machine, as when transmitting the key to some other party.
The key is encoded according to a standard format (such as X.509 or PKCS8), and is returned
using the method:
byte[] getEncoded()
A Format
The name of the format of the encoded key. It is returned by the method:
String getFormat()
Keys are generally obtained through key generators such as the KeyGenerator class and the
KeyPairGenerator class, certificates, key specifications (see the The KeySpec Interface)
using a KeyFactory, or a Keystore implementation accessing a keystore database used to
manage keys. It is possible to parse encoded keys, in an algorithm-dependent manner, using a
KeyFactory.
Here is a list of interfaces which extend the Key interface in the [Link]
and [Link] packages:
• SecretKey
– PBEKey
• PrivateKey
– DHPrivateKey
– DSAPrivateKey
– ECPrivateKey
– RSAMultiPrimePrivateCrtKey
– RSAPrivateCrtKey
– RSAPrivateKey
• PublicKey
– DHPublicKey
– DSAPublicKey
– ECPublicKey
– RSAPublicKey
It has two public methods, one for returning the private key, and the other for returning the
public key:
PrivateKey getPrivate()
PublicKey getPublic()
The KeyFactory and SecretKeyFactory classes can be used to convert between opaque
and transparent key representations (that is, between Keys and KeySpecs, assuming that the
operation is possible. (For example, private keys on smart cards might not be able leave the
card. Such Keys are not convertible.)
In the following sections, we discuss the key specification interfaces and classes in the
[Link] package.
• SecretKeySpec
• EncodedKeySpec
– PKCS8EncodedKeySpec
– X509EncodedKeySpec
• DESKeySpec
• DESedeKeySpec
• PBEKeySpec
• DHPrivateKeySpec
• DSAPrivateKeySpec
• ECPrivateKeySpec
• RSAPrivateKeySpec
– RSAMultiPrimePrivateCrtKeySpec
– RSAPrivateCrtKeySpec
• DHPublicKeySpec
• DSAPublicKeySpec
• ECPublicKeySpec
• RSAPublicKeySpec
and its getFormat method returns the name of the encoding format:
See the next sections for the concrete implementations PKCS8EncodedKeySpec and
X509EncodedKeySpec.
Generators are used to generate brand new objects. Generators can be initialized in either
an algorithm-dependent or algorithm-independent way. For example, to create a Diffie-Hellman
(DH) keypair, an application could specify the necessary P and G values, or the generator
could simply be initialized with the appropriate key length, and the generator will select
appropriate P and G values. In both cases, the generator will produce brand new keys based
on the parameters.
On the other hand, factories are used to convert data from one existing object type to
another. For example, an application might have available the components of a DH private
key and can package them as a The KeySpec Interface, but needs to convert them into a
PrivateKey object that can be used by a KeyAgreement object, or vice-versa. Or they might
have the byte array of a certificate, but need to use a CertificateFactory to convert it into a
X509Certificate object. Applications use factory objects to do the conversion.
Key factories are bi-directional. They allow you to build an opaque key object from a given key
specification (key material), or to retrieve the underlying key material of a key object in a
suitable format.
Multiple compatible key specifications can exist for the same key. For example, a DSA public
key may be specified by its components y, p, q, and g (see
[Link]), or it may be specified using its DER encoding
according to the X.509 standard (see The X509EncodedKeySpec Class).
A key factory can be used to translate between compatible key specifications. Key parsing can
be achieved through translation between compatible key specifications, e.g., when you
translate from X509EncodedKeySpec to DSAPublicKeySpec, you basically parse the encoded key
into its components. For an example, see the end of the Generating/Verifying Signatures Using
Key Specifications and KeyFactory section.
Similarly, if you have a key specification for a private key, you can obtain an opaque
PrivateKey object from the specification by using the generatePrivate method:
keySpec identifies the specification class in which the key material should be returned. It could,
for example, be [Link] , to indicate that the key material should be returned
in an instance of the DSAPublicKeySpec class. See Generating/Verifying Signatures Using Key
Specifications and KeyFactory.
Key factories are used to convert Key Interfaces (opaque cryptographic keys of type
[Link]) into Key Specification Interfaces and Classes (transparent
representations of the underlying key material in a suitable format), and vice versa.
Objects of type [Link], of which [Link],
[Link], and [Link] are subclasses, are opaque key
objects, because you cannot tell how they are implemented. The underlying implementation is
provider-dependent, and may be software or hardware based. Key factories allow providers to
supply their own implementations of cryptographic keys.
For example, if you have a key specification for a Diffie-Hellman public key, consisting of the
public value y, the prime modulus p, and the base g, and you feed the same specification to
Diffie-Hellman key factories from different providers, the resulting PublicKey objects will most
likely have different underlying implementations.
A provider should document the key specifications supported by its secret key factory. For
example, the SecretKeyFactory for DES keys supplied by the SunJCE provider supports
DESKeySpec as a transparent representation of DES keys, the SecretKeyFactory for DES-EDE
keys supports DESedeKeySpec as a transparent representation of DES-EDE keys, and the
SecretKeyFactory for PBE supports PBEKeySpec as a transparent representation of the
underlying password.
The following is an example of how to use a SecretKeyFactory to convert secret key data into
a SecretKey object, which can be used for a subsequent Cipher operation:
// Note the following bytes are not realistic secret key data
// bytes but are simply supplied as an illustration of using data
// bytes (key material) you already have to build a DESedeKeySpec.
keySpec identifies the specification class in which the key material should be returned. It
could, for example, be [Link], to indicate that the key material should be returned
in an instance of the DESKeySpec class.
There are two ways to generate a key pair: in an algorithm-independent manner, and in an
algorithm-specific manner. The only difference between the two is the initialization of the
object.
See Generating a Pair of Keys for examples of calls to the methods of KeyPairGenerator.
Creating a KeyPairGenerator
All key pair generation starts with a KeyPairGenerator. KeyPairGenerator objects are
obtained by using one of the KeyPairGenerator getInstance() static factory methods. See
How Provider Implementations Are Requested and Supplied.
Initializing a KeyPairGenerator
A key pair generator for a particular algorithm creates a public/private key pair that can be
used with this algorithm. It also associates algorithm-specific parameters with each of the
generated keys.
A key pair generator needs to be initialized before it can generate keys. In most cases,
algorithm-independent initialization is sufficient. But in other cases, algorithm-specific
initialization can be used.
Algorithm-Independent Initialization
All key pair generators share the concepts of a keysize and a source of randomness. The
keysize is interpreted differently for different algorithms. For example, in the case of the DSA
algorithm, the keysize corresponds to the length of the modulus. (See Java Security Standard
Algorithm Names for information about the keysizes for specific algorithms.)
An initialize method takes two universally shared types of arguments:
Another initialize method takes only a keysize argument; it uses a system-provided source
of randomness:
Since no other parameters are specified when you call these algorithm-independent
initialize methods, it is up to the provider what to do about the algorithm-specific
parameters (if any) to be associated with each of the keys.
If the algorithm is a "DSA" algorithm, and the modulus size (keysize) is 512, 768, 1024, 2048,
or 3072, then the SUN provider uses a set of precomputed values for the p, q, and g
parameters. If the modulus size is not one of these values, the SUN provider creates a new set
of parameters. Other providers might have precomputed parameter sets for more than just the
three modulus sizes mentioned previously. Still others might not have a list of precomputed
parameters at all and instead always create new parameter sets.
Algorithm-Specific Initialization
For situations where a set of algorithm-specific parameters already exists (such as "community
parameters" in DSA), there are two initialize methods that have an The
AlgorithmParameterSpec Interface argument. One also has a SecureRandom argument, while
the source of randomness is system-provided for the other:
KeyPair generateKeyPair()
Creating a KeyGenerator
KeyGenerator objects are obtained by using one of the KeyGenerator getInstance() static
factory methods. See How Provider Implementations Are Requested and Supplied.
Since no other parameters are specified when you call these algorithm-independent init
methods, it is up to the provider what to do about the algorithm-specific parameters (if any)
to be associated with the generated key.
• Algorithm-Specific Initialization
For situations where a set of algorithm-specific parameters already exists, there are two
init methods that have an AlgorithmParameterSpec argument. One also has a
SecureRandom argument, while the source of randomness is system-provided for the other:
In case the client does not explicitly initialize the KeyGenerator (via a call to an init method),
each provider must supply (and document) a default initialization.
Creating a Key
The following method generates a secret key:
Each party initializes their key agreement object with their private key, and then enters the
public keys for each party that will participate in the communication. In most cases, there are
just two parties, but algorithms such as Diffie-Hellman allow for multiple parties (3 or more) to
participate. When all the public keys have been entered, each KeyAgreement object will
generate (agree upon) the same key.
The KeyAgreement class provides the functionality of a key agreement protocol. The keys
involved in establishing a shared secret are created by one of the key generators
(KeyPairGenerator or KeyGenerator), a KeyFactory, or as a result from an intermediate phase
of the key agreement protocol.
The key parameter contains the key to be processed by that phase. In most cases, this is the
public key of one of the other parties involved in the key agreement, or an intermediate key
that was generated by a previous phase. doPhase may return an intermediate key that you may
have to send to the other parties of this key agreement, so they can process it in a subsequent
phase.
The lastPhase parameter specifies whether or not the phase to be executed is the last one in
the key agreement: A value of FALSE indicates that this is not the last phase of the key
agreement (there are more phases to follow), and a value of TRUE indicates that this is the last
phase of the key agreement and the key agreement is completed, i.e., generateSecret can be
called next.
In the example of Diffie-Hellman Key Exchange between Two Parties , you call doPhase once,
with lastPhase set to TRUE. In the example of Diffie-Hellman between three parties, you call
doPhase twice: the first time with lastPhase set to FALSE, the 2nd time with lastPhase set to
TRUE.
Key Management
A database called a "keystore" can be used to manage a repository of keys and certificates. (A
certificate is a digitally signed statement from one entity, saying that the public key of some
other entity has a particular value.)
Keystore Location
The user keystore is by default stored in a file named .keystore in the user's home directory,
as determined by the [Link] system property whose default value depends on the
operating system:
• Solaris, Linux, and MacOS: /home/username/
• Windows: C:\Users\username\
Of course, keystore files can be located as desired. In some environments, it may make sense
for multiple keystores to exist. For example, one keystore might hold a user's private keys, and
another might hold certificates used to establish trust relationships.
In addition to the user's keystore, the JDK also maintains a system-wide keystore which is
used to store trusted certificates from a variety of Certificate Authorities (CA's). These CA
certificates can be used to help make trust decisions. For example, in SSL/TLS/DTLS when
the SunJSSE provider is presented with certificates from a remote peer, the default
trustmanager will consult one of the following files to determine if the connection is to be
trusted:
• Solaris, Linux, and MacOS: <java-home>/lib/security/cacerts
• Windows: <java-home>\lib\security\cacerts
Instead of using the system-wide cacerts keystore, applications can set up and use their own
keystores, or even use the user keystore described previously.
Keystore Implementation
The KeyStore class supplies well-defined interfaces to access and modify the information in a
keystore. It is possible for there to be multiple different concrete implementations, where each
implementation is that for a particular type of keystore.
Currently, there are two command-line tools that make use of KeyStore: keytool and
jarsigner. It is also used by the Policy reference implementation when it processes policy
files specifying the permissions (allowed accesses to system resources) to be granted to code
from various sources. Since KeyStore is publicly available, JDK users can write additional
security applications that use it.
Applications can choose different types of keystore implementations from different providers,
using the getInstance factory method in the KeyStore class. A keystore type defines the
storage and data format of the keystore information, and the algorithms used to protect private
keys in the keystore and the integrity of the keystore itself. Keystore implementations of
different types are not compatible.
The default keystore implementation is "pkcs12". This is a cross-platform keystore based on
the RSA PKCS12 Personal Information Exchange Syntax Standard. This standard is primarily
meant for storing or transporting a user's private keys, certificates, and miscellaneous secrets.
Arbitrary attributes can be associated with individual entries in a PKCS12 keystore.
[Link]=pkcs12
To have tools and other applications use a different default keystore implementation, you can
change that line to specify a different type.
Some applications, such as keytool, also let you override the default keystore type (via the -
storetype command-line parameter).
Note
Keystore type designations are case-insensitive. For example, "jks" would be
considered the same as "JKS".
PKCS12 is the default and recommened keystore type. However, there are three other types of
keystores that come with the JDK implementation.
1. "jceks" is an alternate proprietary keystore format to "jks" that uses Password-Based
Encryption with Triple-DES.
The "jceks" implementation can parse and convert a "jks" keystore file to the "jceks"
format. You may upgrade your keystore of type "jks" to a keystore of type "jceks" by
changing the password of a private-key entry in your keystore and specifying "-storetype
jceks" as the keystore type. To apply the cryptographically strong(er) key protection
supplied to a private key named "signkey" in your default keystore, use the following
command, which will prompt you for the old and new key passwords:
This class represents an in-memory collection of keys and certificates. KeyStore manages two
types of entries:
• Key Entry: This type of keystore entry holds very sensitive cryptographic key information,
which must be protected from unauthorized access. Typically, a key stored in this type of
entry is a secret key, or a private key accompanied by the certificate chain authenticating
the corresponding public key.
Private keys and certificate chains are used by a given entity for self-authentication using
digital signatures. For example, software distribution organizations digitally sign JAR files
as part of releasing and/or licensing software.
• Trusted Certificate Entry: This type of entry contains a single public key certificate
belonging to another party. It is called a trusted certificate because the keystore owner
trusts that the public key in the certificate indeed belongs to the identity identified by the
subject (owner) of the certificate.
This type of entry can be used to authenticate other parties.
Each entry in a keystore is identified by an "alias" string. In the case of private keys and their
associated certificate chains, these strings distinguish among the different ways in which the
entity may authenticate itself. For example, the entity may authenticate itself using different
certificate authorities, or using different public key algorithms.
Whether keystores are persistent, and the mechanisms used by the keystore if it is persistent,
are not specified here. This convention allows use of a variety of techniques for protecting
sensitive (e.g., private or secret) keys. Smart cards or other integrated cryptographic engines
(SafeKeyper) are one option, and simpler mechanisms such as files may also be used (in a
variety of formats).
The following describes the main KeyStore methods.
The optional password is used to check the integrity of the keystore data. If no password is
supplied, no integrity check is performed.
To create an empty keystore, you pass null as the InputStream argument to the load
method.
A DKS keystore is loaded by passing a DomainLoadStoreParameter to the alternative load
method:
If alias doesn't exist, a trusted certificate entry with that alias is created. If alias exists and
identifies a trusted certificate entry, the certificate associated with it is replaced by cert.
The setKeyEntry methods add (if alias doesn't yet exist) or set key entries:
In the method with key as a byte array, it is the bytes for a key in protected format. For
example, in the keystore implementation supplied by the SUN provider, the key byte array is
expected to contain a protected private key, encoded as an EncryptedPrivateKeyInfo as
defined in the PKCS8 standard. In the other method, the password is the password used to
protect the key.
The deleteEntry method deletes an entry:
PKCS #12 keystores support entries containing arbitrary attributes. Use the PKCS12Attribute
class to create the attributes. When creating the new keystore entry use a constructor method
that accepts attributes. Finally, use the following method to add the entry to the keystore:
The following methods return the certificate, or certificate chain, respectively, associated with
the given alias:
You can determine the name (alias) of the first entry whose certificate matches a given
certificate via the following:
PKCS #12 keystores support entries containing arbitrary attributes. Use the following method
to retrieve an entry that may contain attributes:
and then use the [Link] method to extract such attributes and use
the methods of the [Link] interface to examine them.
The password is used to calculate an integrity checksum of the keystore data, which is
appended to the keystore data.
A DKS keystore is stored by passing a DomainLoadStoreParameter to the alternative store
method:
Depending on the use situation, algorithms can use the parameters directly, or the parameters
might need to be converted into a more portable format for transmission or storage.
A transparent representation of a set of parameters (through AlgorithmParameterSpec) means
that you can access each parameter value in the set individually. You can access these values
through one of the get methods defined in the corresponding specification class (for example,
DSAParameterSpec defines getP, getQ, and getG methods, to access p, q, and g, respectively).
• DHParameterSpec
• DHGenParameterSpec
• DSAParameterSpec
• ECGenParameterSpec
• ECParameterSpec
• GCMParameterSpec
• IvParameterSpec
• MGF1ParameterSpec
• OAEPParameterSpec
• OAEPParameterSpec
• PSSParameterSpec
• RC2ParameterSpec
• RC5ParameterSpec
• RSAKeyGenParameterSpec
In these init methods, params is an array containing the encoded parameters, and format is
the name of the decoding format. In the init method with a params argument but no format
argument, the primary decoding format for parameters is used. The primary decoding format is
ASN.1, if an ASN.1 specification for the parameters exists.
byte[] getEncoded()
This method returns the parameters in their primary encoding format. The primary encoding
format for parameters is ASN.1, if an ASN.1 specification for this type of parameters exists.
If you want the parameters returned in a specified encoding format, use
If format is null, the primary encoding format for parameters is used, as in the other
getEncoded method.
paramSpec identifies the specification class in which the parameters should be returned. The
specification class could be, for example, [Link] to indicate that the
parameters should be returned in an instance of the DSAParameterSpec class. (This class is in
the [Link] package.)
Another init method takes only a size argument and uses a system-provided source of
randomness:
To generate Diffie-Hellman system parameters, for example, the parameter generation values
usually consist of the size of the prime modulus and the size of the random exponent, both
specified in number of bits.
A certificate factory for X.509 must return certificates that are an instance of
[Link].X509Certificate, and CRLs that are an instance of
[Link].X509CRL.
To return a (possibly empty) collection view of the certificates read from a given input stream,
use the generateCertificates method:
To return a (possibly empty) collection view of the CRLs read from a given input stream, use
the generateCRLs method:
To generate a CertPath object and initialize it with a list of certificates, use the following
method:
To retrieve a list of the CertPath encoding supported by this certificate factory, you can call the
getCertPathEncodings method:
Standard Names
The Standard Names document contains information about the algorithm specifications.
Java Security Standard Algorithm Names describes the standard names for algorithms,
certificate and keystore types that the JDK Security API requires and uses. It also contains
more information about the algorithm specifications. Specific provider information can be found
in JDK Providers Documentation.
Cryptographic implementations in the JDK are distributed through several different providers
primarily for historical reasons (Sun, SunJSSE, SunJCE, SunRsaSign). Note these providers may
not be available on all JDK implementations, and therefore, truly portable applications should
call getInstance() without specifying specific providers. Applications specifying a particular
provider may not be able to take advantage of native providers tuned for an underlying
operating environment (such as PKCS or Microsoft's CAPI).
The SunPKCS11 provider itself does not contain any cryptographic algorithms, but instead,
directs requests into an underlying PKCS11 implementation. Consult the PKCS#11 Reference
Guide and the underlying PKCS11 implementation to determine if a desired algorithm will be
available through the PKCS11 provider. Likewise, on Windows systems, the SunMSCAPI
provider does not provide any cryptographic functionality, but instead routes requests to the
underlying operating system for handling.
Note
The details presented here simply show how some of these classes might be
employed. This section will not present sufficient information for building a SSL/TLS
implementation. For more information, see Java Secure Socket Extension (JSSE)
Reference Guide and RFC 5246: The Transport Layer Security (TLS) Protocol,
Version 1.2.
Assume that this SSL/TLS implementation will be made available as a JSSE provider. A
concrete implementation of the Provider class is first written that will eventually be registered
in the Security class' list of providers. This provider mainly provides a mapping from algorithm
names to actual implementation classes. (that is: "[Link]"->"[Link]")
When an application requests an "TLS" instance (via [Link]("TLS")), the
provider's list is consulted for the requested algorithm, and an appropriate instance is created.
Before discussing details of the actual handshake, a quick review of some of the JSSE's
architecture is needed. The heart of the JSSE architecture is the SSLContext. The context
eventually creates end objects (SSLSocket and SSLEngine) which actually implement the
SSL/TLS protocol. SSLContexts are initialized with two callback classes, KeyManager and
TrustManager, which allow applications to first select authentication material to send and
second to verify credentials sent by a peer.
A JSSE KeyManager is responsible for choosing which credentials to present to a peer. Many
algorithms are possible, but a common strategy is to maintain a RSA or DSA public/private key
pair along with a X509Certificate in a KeyStore backed by a disk file. When a KeyStore
object is initialized and loaded from the file, the file's raw bytes are converted into PublicKey
and PrivateKey objects using a KeyFactory, and a certificate chain's bytes are converted
using a CertificateFactory. When a credential is needed, the KeyManager simply consults
this KeyStore object and determines which credentials to present.
A KeyStore's contents might have originally been created using a utility such as keytool.
keytool creates a RSA or DSA KeyPairGenerator and initializes it with an appropriate
keysize. This generator is then used to create a KeyPair which keytool would store along with
the newly-created certificate in the KeyStore, which is eventually written to disk.
A JSSE TrustManager is responsible for verifying the credentials received from a peer. There
are many ways to verify credentials: one of them is to create a CertPath object, and let the
JDK's built-in Public Key Infrastructure (PKI) framework handle the validation. Internally, the
CertPath implementation might create a Signature object, and use that to verify that the each
of the signatures in the certificate chain.
With this basic understanding of the architecture, we can look at some of the steps in the
SSL/TLS handshake. The client begins by sending a ClientHello message to the server. The
server selects a ciphersuite to use, and sends that back in a ServerHello message, and begins
creating JCA objects based on the suite selection. We'll use server-only authentication in the
following examples.
Server-only authentication is described in the following examples. The examples are vastly
simplified, but gives an idea of how the JSSE classes might be combined to create a higher
level protocol:
Example 2-9 SSL/TLS Server Uses a RSA-based ciphersuite Such as
TLS_RSA_WITH_AES_128_CBC_SHA
KeyManagerTrustManagerSecureRandomCipherPublicKeyPrivateKeyCipher
Note
Properties in the [Link] file are typically parsed only once. If you have
modified any property in this file, restart your applications to ensure that the changes
are properly reflected.
The JDK comes bundled with two such directories, limited and unlimited, each containing a
number of policy files. By default, the [Link] Security Property is set to:
[Link] = unlimited
The overall value is the intersection of the files contained within the directory. These policy files
settings are VM-wide, and affect all applications running on this VM. If you want to override
cryptographic strength at the application level, see How to Make Applications Exempt from
Cryptographic Restrictions.
• <java_home>/conf/security/unlimited/default_US_export.policy
Note
As there are no current restrictions on export of cryptography from the United
States, the default_US_export.policy file is set with no restrictions.
• <java_home>/conf/security/unlimited/default_local.policy
Note
Depending on the country, there may be local restrictions, but as this policy file is
located in the unlimited directory, there are no restrictions listed here.
To select unlimited cryptographic strength as defined in these two files set [Link] =
unlimited in the file <java_home>/conf/security/[Link].
• <java_home>/conf/security/limited/default_US_export.policy
Note
Even though this is in the limited directory, as there are no current restrictions on
export of cryptography from the United States, the
default_US_export.policy file is set with no restrictions.
• <java_home>/conf/security/limited/default_local.policy
// Some countries have import limits on crypto strength. This policy file
// is worldwide importable.
grant {
permission [Link] "DES", 64;
permission [Link] "DESede", *;
permission [Link] "RC2", 128,
"[Link].RC2ParameterSpec",
128;
permission [Link] "RC4", 128;
permission [Link] "RC5", 128,
"[Link].RC5ParameterSpec", *, 12, *;
permission [Link] "RSA", *;
permission [Link] *, 128;
};
Note
This local policy file shows the default restrictions. It should be allowed by any
country, including those that have import restrictions, but please obtain legal
guidance.
• <java_home>/conf/security/limited/exempt_local.policy
// Some countries have import limits on crypto strength, but may allow for
// these exemptions if the exemption mechanism is used.
grant {
// There is no restriction to any algorithms if KeyRecovery is
enforced.
permission [Link] *, "KeyRecovery";
Note
Countries that have import restrictions should use “limited”, but these restrictions
could be relaxed if the exemption mechanism can be employed. See How to Make
Applications Exempt from Cryptographic Restrictions. Please obtain legal
guidance for your situation.
To select cryptographic strength as defined in the files in the custom directory, set
[Link] = custom in the file <java_home>/conf/security/[Link].
grant {
<permission entries>;
};
A sample jurisdiction policy file that includes restricting the AES algorithm to maximum key
sizes of 128 bits is:
grant {
permission [Link] "AES", 128;
// ...
};
A permission entry must begin with the word permission. Items that appear in a permission
entry must appear in the specified order. An entry is terminated with a semicolon. Case is
unimportant for the identifiers (grant, permission) but is significant for the <crypto
permission class name> or for any string that is passed in as a value. An asterisk (*) can be
used as a wildcard for any permission entry option. For example, an asterisk for an <alg_name>
option means "all algorithms."
The following table describes a permission entry's options:
Option Description
<crypto permission class name> Specific permission class name, such as
[Link]. Required.
A crypto permission class reflects the ability of an
application to use certain algorithms with certain
key sizes in certain environments. There are two
crypto permission classes: CryptoPermission
and CryptoAllPermission. The special
CryptoAllPermission class implies all
cryptography-related permissions, that is, it
specifies that there are no cryptography-related
restrictions.
<alg_name> Quoted string specifying the standard name of a
cryptography algorithm, such as "AES" or "RSA".
Optional.
<exemption mechanism name> Quoted string indicating an exemption mechanism
which, if enforced, enables a reduction in
cryptographic restrictions. Optional.
Exemption mechanism names that can be used
include "KeyRecovery" "KeyEscrow", and
"KeyWeakening".
<maxKeySize> Integer specifying the maximum key size (in bits)
allowed for the specified algorithm. Optional.
<AlgorithmParameterSpec class name> Class name that specifies the strength of the
algorithm. Optional.
For some algorithms, it may not be sufficient to
specify the algorithm strength in terms of just a key
size. For example, in the case of the "RC5"
algorithm, the number of rounds must also be
considered. For algorithms whose strength needs
to be expressed as more than a key size, use this
option to specify the AlgorithmParameterSpec
class name that does this (such as
[Link].RC5ParameterSpec for the
"RC5" algorithm).
Option Description
<parameters for constructing an List of parameters for constructing the specified
AlgorithmParameterSpec object> AlgorithmParameterSpec object. Required if
<AlgorithmParameterSpec class name> has
been specified and requires parameters.
NOT_SUPPORTED
This section should be ignored by most application developers. It is only for people
whose applications may be exported to those few countries whose governments
mandate cryptographic restrictions, if it is desired that such applications have fewer
cryptographic restrictions than those mandated.
By default, an application can use cryptographic algorithms of any strength. However, due to
import control restrictions by the governments of a few countries, you may have to limit those
algorithms' strength. The JCA framework includes an ability to enforce restrictions regarding
the maximum strengths of cryptographic algorithms available to applications in different
jurisdiction contexts (locations). You specify these restrictions in jurisdiction policy files. For
more information about jurisdiction policy files and how to create and configure them, see
Cryptographic Strength Configuration.
It is possible that the governments of some or all such countries may allow certain applications
to become exempt from some or all cryptographic restrictions. For example, they may consider
certain types of applications as "special" and thus exempt. Or they may exempt any application
that utilizes an "exemption mechanism," such as key recovery. Applications deemed to be
exempt could get access to stronger cryptography than that allowed for non-exempt
applications in such countries.
In order for an application to be recognized as "exempt" at runtime, it must meet the following
conditions:
• It must have a permission policy file bundled with it in a JAR file. The permission policy file
specifies what cryptography-related permissions the application has, and under what
conditions (if any).
• The JAR file containing the application and the permission policy file must have been
signed using a code-signing certificate issued after the application was accepted as
exempt.
The following are sample steps required in order to make an application exempt from some
cryptographic restrictions. This is a basic outline that includes information about what is
required by JCA in order to recognize and treat applications as being exempt. You will need to
know the exemption requirements of the particular country or countries in which you would like
your application to be able to be run but whose governments require cryptographic restrictions.
You will also need to know the requirements of a JCA framework vendor that has a process in
place for handling exempt applications. Consult such a vendor for further information.
Note
The SunJCE provider does not supply an implementation of the
ExemptionMechanismSpi class
After instantiating a Cipher, and prior to initializing it (via a call to the Cipher init method), your
code must call the following Cipher method:
This call returns the ExemptionMechanism object associated with the Cipher. You must then
initialize the exemption mechanism implementation by calling the following method on the
returned ExemptionMechanism:
The argument you supply should be the same as the argument of the same types that you will
subsequently supply to a Cipher init method.
Once you have initialized the ExemptionMechanism, you can proceed as usual to initialize and
use the Cipher.
grant {
// There are no restrictions to any algorithms.
permission [Link];
};
If an application just uses a single algorithm (or several specific algorithms), then the
permission policy file could simply mention that algorithm (or algorithms) explicitly, rather than
granting CryptoAllPermission.
For example, if an application just uses the Blowfish algorithm, the permission policy file
doesn't have to grant CryptoAllPermission to all algorithms. It could just specify that there
is no cryptographic restriction if the Blowfish algorithm is used. In order to do this, the
permission policy file would look like the following:
grant {
permission [Link] "Blowfish";
};
grant {
// No algorithm restrictions if KeyRecovery is enforced.
permission [Link] *, "KeyRecovery";
Note
Permission entries that specify exemption mechanisms should not also specify
maximum key sizes. The allowed key sizes are actually determined from the installed
exempt jurisdiction policy files, as described in the next section.
Topics
Computing a MessageDigest Object
Generating a Pair of Keys
Generating and Verifying a Signature Using Generated Keys
Generating/Verifying Signatures Using Key Specifications and KeyFactory
Determining If Two Keys Are Equal
Reading Base64-Encoded Certificates
Parsing a Certificate Reply
Using Encryption
Using Password-Based Encryption
This call assigns a properly initialized message digest object to the sha variable. The
implementation implements the Secure Hash Algorithm (SHA-256), as defined in the
National Institute for Standards and Technology's (NIST) FIPS 180-4 document.
2. Suppose we have three byte arrays, i1, i2 and i3, which form the total input whose
message digest we want to compute. This digest (or "hash") could be calculated via the
following calls:
[Link](i1);
[Link](i2);
[Link](i3);
byte[] hash = [Link]();
[Link](i1);
[Link](i2);
byte[] hash = [Link](i3);
After the message digest has been calculated, the message digest object is automatically
reset and ready to receive new data and calculate its digest. All former state (i.e., the data
supplied to update calls) is lost.
Example 2-11 Hash Implementations Through Cloning
Some hash implementations may support intermediate hashes through cloning. Suppose we
want to calculate separate hashes for:
• i1
• i1 and i2
• i1, i2, and i3
The following is one way to calculate these hashes; however, this code works only if the
SHA-256 implementation is cloneable:
try {
// try and clone it
/* compute the hash for i1 */
[Link](i1);
byte[] i1Hash = [Link]().digest();
// ...
byte[] i123hash = [Link]();
} catch (CloneNotSupportedException cnse) {
// do something else, such as the code in the section
// "Compute Intermediate Digests if the Hash Implementation is not
Cloneable"
}
[Link](i1);
byte[] i12Hash = [Link](i2);
[Link](i1);
[Link](i2);
byte[] i123Hash = [Link](i3);
Algorithm-Independent Initialization
All key pair generators share the concepts of a keysize and a source of randomness. The
KeyPairGenerator class initialization methods at a minimum needs a keysize. If the source of
randomness is not explicitly provided, a SecureRandom implementation of the highest-priority
installed provider will be used. Thus to generate keys with a keysize of 2048, simply call:
[Link](2048);
The following code illustrates how to use a specific, additionally seeded SecureRandom object:
Since no other parameters are specified when you call these algorithm-independent
initialize method, it is up to the provider what to do about the algorithm-specific
parameters (if any) to be associated with each of the keys. The provider may use precomputed
parameter values or may generate new values.
Algorithm-Specific Initialization
For situations where a set of algorithm-specific parameters already exists (such as "community
parameters" in DSA), there are two initialize methods that have an
AlgorithmParameterSpec argument. Suppose your key pair generator is for the "DSA"
algorithm, and you have a set of DSA-specific parameters, p, q, and g, that you would like to
use to generate your key pair. You could execute the following code to initialize your key pair
generator (recall that DSAParameterSpec is an AlgorithmParameterSpec):
Generating a Signature
We first create a Signature Class object:
Next, using the key pair generated in the key pair example, we initialize the object with the
private key, then sign a byte array called data.
[Link](data);
byte[] sig = [Link]();
Verifying a Signature
Verifying the signature is straightforward. (Note that here we also use the key pair generated in
the key pair example.)
Furthermore, suppose you want to use your private key to digitally sign some data, which is in
a byte array named someData. You would do the following steps, which also illustrate creating a
key specification and using a key factory to obtain a PrivateKey from the key specification
(initSign requires a PrivateKey):
Suppose Alice wants to use the data you signed. In order for her to do so, and to verify your
signature, you need to send her three things:
1. The data
2. The signature
3. The public key corresponding to the private key you used to sign the data
You can store the someData bytes in one file, and the signature bytes in another, and send
those to Alice.
For the public key, assume, as in the previous signing example, you have the components of
the DSA public key corresponding to the DSA private key used to sign the data. Then you can
create a DSAPublicKeySpec from those components:
You still need to extract the key bytes so that you can put them in a file. To do so, you can first
call the generatePublic method on the DSA key factory already created in the previous
example:
Then you can extract the (encoded) key bytes via the following:
You can now store these bytes in a file, and send it to Alice along with the files containing the
data and the signature.
Now, assume Alice has received these files, and she copied the data bytes from the data file to
a byte array named data, the signature bytes from the signature file to a byte array named
signature, and the encoded public key bytes from the public key file to a byte array named
encodedPubKey.
Alice can now execute the following code to verify the signature. The code also illustrates how
to use a key factory in order to instantiate a DSA public key from its encoding (initVerify
requires a PublicKey).
Note
In the previous example, Alice needed to generate a PublicKey from the encoded key
bits, since initVerify requires a PublicKey . Once she has a PublicKey, she could
also use the KeyFactorygetKeySpec method to convert it to a DSAPublicKeySpec so
that she can access the components, if desired, as in:
DSAPublicKeySpec dsaPubKeySpec =
(DSAPublicKeySpec)[Link](pubKey,
[Link]);
Now she can access the DSA public key components y, p, q, and g through the corresponding
"get" methods on the DSAPublicKeySpec class (getY, getP, getQ, and getG).
SecureRandom drbg;
byte[] buffer = new byte[32];
// Both the next two calls will likely fail, because drbg could be
// instantiated with a smaller strength with no prediction resistance
// support.
[Link](buffer,
[Link](256, false, "more".getBytes()));
[Link](buffer,
[Link](112, true, "more".getBytes()));
if ([Link]([Link](), [Link]())) {
return true;
}
return false;
}
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
We convert the FileInputStream (which does not support mark and reset ) to a
ByteArrayInputStream (which supports those methods), so that each call to
generateCertificate consumes only one certificate, and the read position of the input stream
is positioned to the next certificate in the file:
Using Encryption
This section takes the user through the process of generating a key, creating and initializing a
cipher object, encrypting a file, and then decrypting it. Throughout this example, we use the
Advanced Encryption Standard (AES).
Generating a Key
To create an AES key, we have to instantiate a KeyGenerator for AES. We do not specify a
provider, because we do not care about a particular AES key generation implementation. Since
we do not initialize the KeyGenerator, a system-provided source of randomness and a
default keysize will be used to create the AES key:
After the key has been generated, the same KeyGenerator object can be re-used to create
further keys.
Creating a Cipher
The next step is to create a Cipher instance. To do this, we use one of the getInstance
factory methods of the Cipher class. We must specify the name of the requested
transformation, which includes the following components, separated by slashes (/):
Cipher aesCipher;
We use the aesKey generated previously to initialize the Cipher object for encryption:
// Our cleartext
byte[] cleartext = "This is just an example".getBytes();
PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;
// Salt
byte[] salt = new SecureRandom().nextBytes(salt);
// Iteration count
int count = 1000;
// Our cleartext
byte[] cleartext = "This is another example".getBytes();
Topics
Diffie-Hellman Key Exchange between Two Parties
Diffie-Hellman Key Exchange between Three Parties
AES/GCM Example
HMAC-SHA256 Example
import [Link].*;
import [Link];
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
/*
* Alice creates her own DH key pair with 2048-bit key size
*/
[Link]("ALICE: Generate DH keypair ...");
KeyPairGenerator aliceKpairGen = [Link]("DH");
[Link](2048);
KeyPair aliceKpair = [Link]();
/*
* Let's turn over to Bob. Bob has received Alice's public key
* in encoded format.
* He instantiates a DH public key from the encoded key material.
*/
KeyFactory bobKeyFac = [Link]("DH");
X509EncodedKeySpec x509KeySpec = new
X509EncodedKeySpec(alicePubKeyEnc);
/*
* Bob gets the DH parameters associated with Alice's public key.
* He must use the same parameters when he generates his own key
* pair.
*/
DHParameterSpec dhParamFromAlicePubKey =
((DHPublicKey)alicePubKey).getParams();
/*
* Alice uses Bob's public key for the first (and only) phase
* of her version of the DH
* protocol.
* Before she can do so, she has to instantiate a DH public key
* from Bob's encoded key material.
*/
KeyFactory aliceKeyFac = [Link]("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
PublicKey bobPubKey = [Link](x509KeySpec);
[Link]("ALICE: Execute PHASE1 ...");
[Link](bobPubKey, true);
/*
* Bob uses Alice's public key for the first (and only) phase
* of his version of the DH
* protocol.
*/
[Link]("BOB: Execute PHASE1 ...");
[Link](alicePubKey, true);
/*
* At this stage, both Alice and Bob have completed the DH key
* agreement protocol.
* Both generate the (same) shared secret.
*/
try {
byte[] aliceSharedSecret = [Link]();
int aliceLen = [Link];
byte[] bobSharedSecret = new byte[aliceLen];
int bobLen;
} catch (ShortBufferException e) {
[Link]([Link]());
} // provide output buffer of required size
bobLen = [Link](bobSharedSecret, 0);
[Link]("Alice secret: " +
toHexString(aliceSharedSecret));
[Link]("Bob secret: " +
toHexString(bobSharedSecret));
if ()
throw new Exception("Shared secrets differ");
[Link]("Shared secrets are the same");
/*
* Now let's create a SecretKey object using the shared secret
* and use it for encryption. First, we generate SecretKeys for the
* "AES" algorithm (based on the raw shared secret data) and
* Then we use AES in CBC mode, which requires an initialization
* vector (IV) parameter. Note that you have to use the same IV
* for encryption and decryption: If you use a different IV for
* decryption than you used for encryption, decryption will fail.
*
* If you do not specify an IV when you initialize the Cipher
* object for encryption, the underlying implementation will generate
* a random one, which you have to retrieve using the
* [Link]() method, which returns an
* instance of [Link]. You need to transfer
* the contents of that object (e.g., in encoded format, obtained via
* the [Link]() method) to the party who will
* do the decryption. When initializing the Cipher for decryption,
* the (reinstantiated) AlgorithmParameters object must be explicitly
* passed to the [Link]() method.
*/
[Link]("Use shared secret as SecretKey object ...");
SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16,
"AES");
SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0,
16, "AES");
/*
* Bob encrypts, using AES in CBC mode
*/
Cipher bobCipher = [Link]("AES/CBC/PKCS5Padding");
[Link](Cipher.ENCRYPT_MODE, bobAesKey);
byte[] cleartext = "This is just an example".getBytes();
byte[] ciphertext = [Link](cleartext);
/*
* Alice decrypts, using AES in CBC mode
*/
/*
* Converts a byte to hex digit and writes to the supplied buffer
*/
private static void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
[Link](hexChars[high]);
[Link](hexChars[low]);
}
/*
* Converts a byte array to hex string
*/
private static String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = [Link];
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len-1) {
[Link](":");
}
}
return [Link]();
}
}
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
/*
* This program executes the Diffie-Hellman key agreement protocol between
* 3 parties: Alice, Bob, and Carol using a shared 2048-bit DH parameter.
*/
public class DHKeyAgreement3 {
private DHKeyAgreement3() {}
public static void main(String argv[]) throws Exception {
// Alice creates her own DH key pair with 2048-bit key size
[Link]("ALICE: Generate DH keypair ...");
KeyPairGenerator aliceKpairGen =
[Link]("DH");
[Link](2048);
KeyPair aliceKpair = [Link]();
// This DH parameters can also be constructed by creating a
// DHParameterSpec object using agreed-upon values
DHParameterSpec dhParamShared =
((DHPublicKey)[Link]()).getParams();
// Bob creates his own DH key pair using the same params
[Link]("BOB: Generate DH keypair ...");
KeyPairGenerator bobKpairGen = [Link]("DH");
[Link](dhParamShared);
KeyPair bobKpair = [Link]();
// Carol creates her own DH key pair using the same params
[Link]("CAROL: Generate DH keypair ...");
KeyPairGenerator carolKpairGen =
[Link]("DH");
[Link](dhParamShared);
KeyPair carolKpair = [Link]();
// Alice initialize
[Link]("ALICE: Initialize ...");
KeyAgreement aliceKeyAgree = [Link]("DH");
[Link]([Link]());
// Bob initialize
[Link]("BOB: Initialize ...");
KeyAgreement bobKeyAgree = [Link]("DH");
[Link]([Link]());
// Carol initialize
[Link]("CAROL: Initialize ...");
KeyAgreement carolKeyAgree = [Link]("DH");
[Link]([Link]());
// Alice uses Carol's public key
Key ac = [Link]([Link](), false);
// Bob uses Alice's public key
Key ba = [Link]([Link](), false);
// Carol uses Bob's public key
Key cb = [Link]([Link](), false);
// Alice uses Carol's result, cb
[Link](cb, true);
// Bob uses Alice's result, ac
[Link](ac, true);
// Carol uses Bob's result, ba
[Link](ba, true);
// Alice, Bob and Carol compute their secrets
byte[] aliceSharedSecret = [Link]();
[Link]("Alice secret: " +
toHexString(aliceSharedSecret));
byte[] bobSharedSecret = [Link]();
[Link]("Bob secret: " + toHexString(bobSharedSecret));
byte[] carolSharedSecret = [Link]();
[Link]("Carol secret: " +
toHexString(carolSharedSecret));
// Compare Alice and Bob
if ()
throw new Exception("Alice and Bob differ");
[Link]("Alice and Bob are the same");
// Compare Bob and Carol
if ()
throw new Exception("Bob and Carol differ");
[Link]("Bob and Carol are the same");
}
/*
* Converts a byte to hex digit and writes to the supplied buffer
*/
AES/GCM Example
The following is a sample program to demonstrate AES/GCM usage to encrypt/decrypt data.
import [Link];
import [Link];
import [Link].*;
if ([Link](data, dec) != 0) {
throw new Exception("Original data != decrypted data");
}
}
}
HMAC-SHA256 Example
The following is a sample program that demonstrates how to generate a secret-key object for
HMAC-SHA256, and initialize a HMAC-SHA256 object with it.
Example 2-14 Generate a Secret-key Object for HMAC-SHA256
import [Link].*;
import [Link].*;
/**
* This program demonstrates how to generate a secret-key object for
* HMACSHA256, and initialize an HMACSHA256 object with it.
*/
Notes on Terminology
Throughout this document, the terms JCA by itself refers to the JCA framework. Whenever this
document notes a specific JCA provider, it will be referred to explicitly by the provider name.
• Prior to JDK 1.4, the JCE was an unbundled product, and as such, the JCA and JCE were
regularly referred to as separate, distinct components. As JCE is now bundled in JDK, the
distinction is becoming less apparent. Since the JCE uses the same architecture as the
JCA, the JCE should be more properly thought of as a subset of the JCA.
• The JCA within the JDK includes two software components:
– the framework that defines and supports cryptographic services for which providers
supply implementations. This framework includes packages such as [Link],
[Link], [Link], and [Link].
– the actual providers such as Sun, SunRsaSign, SunJCE, which contain the actual
cryptographic implementations.
• The JCE consists of the [Link].* packages and the SunJCE provider.
standard interface. An application may rely on multiple independent providers for security
functionality.
• Implementation interoperability: Providers are interoperable across applications.
Specifically, an application is not bound to a specific provider, and a provider is not bound
to a specific application.
• Algorithm extensibility: The Java platform includes a number of built-in providers that
implement a basic set of security services that are widely used today. However, some
applications may rely on emerging standards not yet implemented, or on proprietary
services. The Java platform supports the installation of custom providers that implement
such services.
A Cryptographic Service Provider (provider) refers to a package (or a set of packages) that
supply a concrete implementation of a subset of the cryptography aspects of the JDK Security
API.
The [Link] class encapsulates the notion of a security provider in the
Java platform. It specifies the provider's name and lists the security services it implements.
Multiple providers may be configured at the same time, and are listed in order of preference.
When a security service is requested, the highest priority provider that implements that service
is selected. See Security Providers, which illustrates how a provider selects a requested
security service.
• KeyPairGenerator - used to generate a pair of public and private keys suitable for a
specified algorithm.
• KeyFactory - used to convert opaque cryptographic keys of type Key into key specifications
(transparent representations of the underlying key material), and vice versa.
• KeyStore - used to create and manage a keystore. A keystore is a database of keys.
Private keys in a keystore have a certificate chain associated with them, which
authenticates the corresponding public key. A keystore also contains certificates from
trusted entities.
• CertificateFactory - used to create public key certificates and Certificate Revocation
Lists (CRLs).
• AlgorithmParameters - used to manage the parameters for a particular algorithm,
including parameter encoding and decoding.
• AlgorithmParameterGenerator - used to generate a set of parameters suitable for a
specified algorithm.
• SecureRandom - used to generate random or pseudo-random numbers.
• Cipher - used to encrypt or decrypt some specified data.
• KeyAgreement - used to execute a key agreement (key exchange) protocol between 2 or
more parties.
• KeyGenerator - used to generate a secret (symmetric) key suitable for a specified
algorithm.
• Mac: used to compute the message authentication code of some specified data.
• SecretKeyFactory - used to convert opaque cryptographic keys of type SecretKey into key
specifications (transparent representations of the underlying key material), and vice versa.
• CertPathBuilder - used to create public key certificates and Certificate Revocation Lists
(CRLs).
• CertPathValidator - used to validate certificate chains.
• CertStore - used to retrieve Certificates and CRLs from a repository.
• ExemptionMechanism - used to provide the functionality of an exemption mechanism such
as key recovery, key weakening, key escrow, or any other (custom) exemption
mechanism. Applications that use an exemption mechanism may be granted stronger
encryption capabilities than those which don't. However, please note that cryptographic
restrictions are no longer required for most countries, and thus exemption mechanisms
may only be useful in those few countries whose governments mandate restrictions.
Note
A generator creates objects with brand-new contents, whereas a factory creates
objects from existing material (for example, an encoding).
An engine class provides the interface to the functionality of a specific type of cryptographic
service (independent of a particular cryptographic algorithm). It defines Application
Programming Interface (API) methods that allow applications to access the specific type of
cryptographic service it provides. The actual implementations (from one or more providers) are
those for specific algorithms. For example, the Signature engine class provides access to the
functionality of a digital signature algorithm. The actual implementation supplied in a
SignatureSpi subclass (see next paragraph) would be that for a specific kind of signature
algorithm, such as SHA256withDSA or SHA512withRSA.
The application interfaces supplied by an engine class are implemented in terms of a Service
Provider Interface (SPI). That is, for each engine class, there is a corresponding abstract SPI
class, which defines the Service Provider Interface methods that cryptographic service
providers must implement.
An instance of an engine class, the "API object", encapsulates (as a private field) an instance
of the corresponding SPI class, the "SPI object". All API methods of an API object are declared
"final", and their implementations invoke the corresponding SPI methods of the encapsulated
SPI object. An instance of an engine class (and of its corresponding SPI class) is created by a
call to the getInstance factory method of the engine class.
The name of each SPI class is the same as that of the corresponding engine class, followed by
"Spi". For example, the SPI class corresponding to the Signature engine class is the
SignatureSpi class.
Each SPI class is abstract. To supply the implementation of a particular type of service and for
a specific algorithm, a provider must subclass the corresponding SPI class and provide
implementations for all the abstract methods.
Another example of an engine class is the MessageDigest class, which provides access to a
message digest algorithm. Its implementations, in MessageDigestSpi subclasses, may be
those of various message digest algorithms such as SHA-256 or SHA-384.
As a final example, the KeyFactory engine class supports the conversion from opaque keys to
transparent key specifications, and vice versa. See Key Specification Interfaces and Classes
Required by Key Factories. The actual implementation supplied in a KeyFactorySpi subclass
would be that for a specific type of keys, e.g., DSA public and private keys.
• MacSpi
• SecretKeyFactorySpi
• ExemptionMechanismSpi
To know more about the JCA and other cryptographic classes, see Engine Classes and
Corresponding Service Provider Interface Classes.
In the subclass, you need to:
1. Supply implementations for the abstract methods, whose names usually begin with engine.
See Further Implementation Details and Requirements.
2. Depending on how you write your provider and register its algorithms (using either String
objects or the [Link] class), the provider either:
• Ensure that there is a public constructor without any arguments. Here's why: When
one of your services is requested, Java Security looks up the subclass implementing
that service, as specified by a property in your "master class" (see Step 3: Write Your
Master Class, a Subclass of Provider). Java Security then creates the Class object
associated with your subclass, and creates an instance of your subclass by calling the
newInstance method on that Class object. newInstance requires your subclass to
have a public constructor without any parameters. (A default constructor without
arguments will automatically be generated if your subclass doesn't have any
constructors. But if your subclass defines any constructors, you must explicitly define a
public constructor without arguments.)
• Override the newInstance() method in the registered [Link]. This is
the preferred mechanism in JDK 9 and later.
Step 1.1: Consider Additional JCA Provider Requirements and Recommendations for
Encryption Implementations
When instantiating a provider's implementation (class) of a Cipher, KeyAgreement,
KeyGenerator, MAC, or SecretKey factory, the framework will determine the provider's codebase
(JAR file) and verify its signature. In this way, JCA authenticates the provider and ensures that
only providers signed by a trusted entity can be plugged into the JCA. Thus, one requirement
for encryption providers is that they must be signed, as described in later steps.
In order for provider classes to become unusable if instantiated by an application directly,
bypassing JCA, providers should implement the following:
• All SPI implementation classes in a provider package should be declared final (so that
they cannot be subclassed), and their (SPI) implementation methods should be declared
protected.
• All crypto-related helper classes in a provider package should have package-private
scope, so that they cannot be accessed from outside the provider package.
For providers that may be exported outside the U.S., CipherSpi implementations must include
an implementation of the engineGetKeySize method which, given a Key, returns the key size. If
there are restrictions on available cryptographic strength specified in jurisdiction policy files,
each Cipher initialization method calls engineGetKeySize and then compares the result with
the maximum allowable key size for the particular location and circumstances of the application
being run. If the key size is too large, the initialization method throws an exception.
Additional optional features that providers may implement are:
• Create a provider that registers its services with String objects to store algorithm names
and their associated implementation class name. These are stored in the
Hashtable<Object,Object> superclass of [Link].
• Create a provider that uses the [Link] class, which uses a different method
to store algorithm names and create new objects. The [Link] class enables
you customize how the JCA framework requests services from your provider, such as how
the framework creates new instances of your provider's services. This coding style is
recommended, especially when using modules.
A provider can use either style, or even use both styles at the same time. Regardless of which
style you choose, your subclass should be final.
Step 3.1: Create a Provider That Uses String Objects to Register Its Services
The following is an example of a provider that uses String objects to store implemented
algorithm names:
package p;
public final class MyProvider extends Provider {
public MyProvider() {
super("MyProvider", "1.0",
"Some info about my provider and which algorithms it supports");
// [Link] extends CipherSPI
put("[Link]", "[Link]");
}
}
• Call super, specifying the provider name (see Step 2: Give your Provider a Name) version
number, and a string of information about the provider and algorithms it supports.
super("MyProvider", "1.0",
"Some info about my provider and which algorithms it supports");
• Set the values of various properties that are required for the Java Security API to look up
the cryptographic services implemented by the provider.
For each service implemented by the provider, there must be a property whose name is
the type of service followed by a period and the name of the algorithm to which the service
applies. The property value must specify the fully qualified name of the class implementing
the service.
For example, this following statement sets a property named [Link] whose
value is [Link], a class that extends CipherSPI:
put("[Link]", "[Link]");
The following list shows the various types of JCA services, where the actual algorithm
name is substituted for algName:
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]: algName may actually represent a transformation, and may be
composed of an algorithm name, a particular mode, and a padding scheme. See Java
Security Standard Algorithm Names
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]: algName refers to the name of the exemption
mechanism, which can be one of the following: KeyRecovery, KeyEscrow, or
KeyWeakening. Case does not matter.
In all of these except ExemptionMechanism and Cipher, algName is the "standard" name of
the algorithm, certificate type, or keystore type. See Java Security Standard Algorithm
Names for the standard names that should be used.
The value of each property must be the fully qualified name of the class implementing the
specified algorithm, certificate type, or keystore type. That is, it must be the package name
followed by the class name, where the two are separated by a period.
As an example, the default provider named SUN implements the Digital Signature
Algorithm (whose standard name is SHA256withDSA) in a class named DSA in the
[Link] package. Its subclass of Provider (which is the Sun class in the
[Link] package) sets the Signature.SHA256withDSA property to have
the value [Link] via the following:
put("Signature.SHA256withDSA", "[Link]")
The following list shows more properties that can be defined for the various types of
services, where the actual algorithm name is substituted for algName, certificate type for
certType, keystore type for storeType, and attribute name for attrName:
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
– [Link] [one or more spaces] attrName
In each of these, attrName is the "standard" name of the algorithm, certificate type,
keystore type, or attribute. (See Java Security Standard Algorithm Names for the standard
names that should be used.)
For a property in this format, the value of the property must be the value for the
corresponding attribute. (See Java Security Standard Algorithm Names for the definition of
each standard attribute.)
For further master class property setting examples, see the JDK source code for the
[Link] and [Link] classes.
They show how the Sun and SunJCE providers set properties.
As an example, the default provider named SUN implements the SHA256withDSA Digital
Signature Algorithm in software. The class [Link] calls the
method [Link], which sets the properties for the SUN provider,
including setting the property Signature.SHA256withDSA ImplementedIn to have the value
Software:
Note
For examples of this coding style, see the source code for
[Link] and [Link]
classes.
package p;
public MyProvider() {
super("MyProvider", "1.0",
"Some info about my provider and which algorithms it supports");
putService(new ProviderService(this, "Cipher", "MyCipher",
"[Link]"));
}
@Override
public Object newInstance(Object ctrParamObj)
throws NoSuchAlgorithmException {
String type = getType();
String algo = getAlgorithm();
try {
if ([Link]("Cipher")) {
if ([Link]("MyCipher")) {
return new MyCipher();
}
}
} catch (Exception ex) {
throw new NoSuchAlgorithmException(
"Error constructing " + type + " for "
+ algo + " using MyProvider", ex);
}
throw new ProviderException("No impl for " + algo + " " + type);
}
}
}
The following statement adds a service named MyCipher of type Cipher; the name of the
class implementing this service is [Link]. The argument of putService is a subclass
of [Link]:
Note that this example is essentially the same as the example described in Step 3.1:
Create a Provider That Uses String Objects to Register Its Services.
• Override any method in [Link], such as newInstance, to customize how
the JCA framework handles the services in your provider.
The example at the beginning of this section overrides the method
[Link]. The method returns an instance of MyCipher only if
the requested service is MyCipher. If not, it throws a NoSuchAlgorithmException and a
ProviderException.
For more information about other methods you can override, see The [Link]
Class.
Note
For examples of this coding style, see the JDK source code contained in the
[Link] package.
(In the latter case, provider-specific default values for the mode and padding scheme are
used). For example, the following is a valid transformation:
Cipher c = [Link]("AES/CBC/PKCS5Padding");
When requesting a block cipher in stream cipher mode (for example; AES in CFB or OFB mode),
a client may optionally specify the number of bits to be processed at a time, by appending this
number to the mode name as shown in the following sample transformations:
Cipher c1 = [Link]("AES/CFB8/NoPadding");
Cipher c2 = [Link]("AES/OFB32/PKCS5Padding");
If a number does not follow a stream cipher mode, a provider-specific default is used. (For
example, the SunJCE provider uses a default of 128 bits.)
A provider may supply a separate class for each combination of algorithm/mode/padding.
Alternatively, a provider may decide to provide more generic classes representing sub-
transformations corresponding to algorithm or algorithm/mode or algorithm//padding (note the
double slashes); in this case the requested mode and/or padding are set automatically by the
getInstance methods of Cipher, which invoke the engineSetMode and engineSetPadding
methods of the provider's subclass of CipherSpi.
That is, a Cipher property in a provider master class may have one of the formats shown in the
following table:
(See Java Security Standard Algorithm Names for the standard algorithm names, modes, and
padding schemes that should be used.)
For example, a provider may supply a subclass of CipherSpi that implements AES/ECB/
PKCS5Padding, one that implements AES/CBC/PKCS5Padding, one that implements
AES/CFB/PKCS5Padding, and yet another one that implements AES/OFB/PKCS5Padding.
That provider would have the following Cipher properties in its master class:
• [Link]/ECB/PKCS5Padding
• [Link]/CBC/PKCS5Padding
• [Link]/CFB/PKCS5Padding
• [Link]/OFB/PKCS5Padding
Another provider may implement a class for each of these modes (for example, one class for
ECB, one for CBC, one for CFB, and one for OFB), one class for PKCS5Padding, and a
generic AES class that subclasses from CipherSpi. That provider would have the following
Cipher properties in its master class:
• [Link]
• [Link] SupportedModes
– Example: "ECB|CBC|CFB|OFB"
• [Link] SupportedPaddings
– Example: "NOPADDING|PKCS5Padding"
The getInstance factory method of the Cipher engine class follows these rules in order to
instantiate a provider's implementation of CipherSpi for a transformation of the form
"algorithm":
1. Check if the provider has registered a subclass of CipherSpi for the specified "algorithm".
• If the answer is YES, instantiate this class, for whose mode and padding scheme
default values (as supplied by the provider) are used.
• If the answer is NO, throw a NoSuchAlgorithmException exception.
2. The getInstance factory method of the Cipher engine class follows these rules in order to
instantiate a provider's implementation of CipherSpi for a transformation of the form
"algorithm/mode/padding":
a. Check if the provider has registered a subclass of CipherSpi for the specified
"algorithm/mode/padding" transformation.
• If the answer is YES, instantiate it.
• If the answer is NO, go to the next step.
b. Check if the provider has registered a subclass of CipherSpi for the sub-
transformation "algorithm/mode".
• If the answer is YES, instantiate it, and call engineSetPadding(padding) on the
new instance.
• If the answer is NO, go to the next step.
c. Check if the provider has registered a subclass of CipherSpi for the sub-
transformation "algorithm//padding" (note the double slashes)
• If the answer is YES, instantiate it, and call engineSetMode(mode) on the new
instance.
• If the answer is NO, go to the next step.
d. Check if the provider has registered a subclass of CipherSpi for the sub-
transformation "algorithm".
• If the answer is YES, instantiate it, and call engineSetMode(mode) and
engineSetPadding(padding) on the new instance.
• If the answer is NO, throw a NoSuchAlgorithmException exception.
declaration will be ignored. Also, you can still package your providers in unnamed or automatic
modules.
Create a module declaration for your provider and save it in a file named module-
[Link]. This module declaration includes the following:
module [Link] {
provides [Link] with [Link];
requires [Link];
}
[Link]
Note
The [Link] file and the --module-version option are optional.
However, the [Link] file is required if you want to create a modular
JAR file. (A modular JAR file is a regular JAR file that has a [Link] file
in its top-level directory.)
This generates a 2048-bit RSA keypair (a public key and an associated private key) and
stores it in an entry in the specified keystore. The public key is stored in a self-signed
certificate. The keystore entry can subsequently be accessed using the specified alias.
Note
It's recommended that you create a keypair that uses RSA or DSA with 2048 or
more bits.
The option values in angle brackets (< and >) represent the actual values that must be
supplied. For example, <alias> must be replaced with whatever alias name you wish to be
used to refer to the newly-generated keystore entry in the future, and <keystore file
name> must be replaced with the name of the keystore to be used.
Tip
Do not surround actual values with angle brackets. For example, if you want your
alias to be myTestAlias, specify the -alias option as follows:
-alias myTestAlias
Note
If command lines you type are not allowed to be as long as the keytool -
genkeypair command you want to execute (for example, if you are typing to a
Microsoft Windows DOS prompt), you can create and execute a plain-text batch
file containing the command. That is, create a new text file that contains nothing
but the full keytool -genkeypair command. (Remember to type it all on one line.)
Save the file with a .bat extension. Then in your DOS window, type the file name
(with its path, if necessary). This will cause the command in the batch file to be
executed.
Here, <alias> is the alias for the RSA keypair entry created in the previous step. This
command generates a CSR, using the PKCS#10 format. It stores the CSR in the file
whose name is specified in <csr file name>.
3. Request a JCE code signing certificate by sending your CSR, your contact information,
and other required documentation to the JCA Code Signing Certification Authority. See
JCA Code Signing Certification Authority for more information.
4. Once the JCE Code Signing Certification Authority receives your request, they will validate
it and perform a background check. If this check passes, then they will create and sign a
JCE code-signing certificate valid for 5 years. You will receive an email message
containing two text certificates: the code-signing certificate and the JCE CA certificate,
which authenticates the code-signing certificate's public key.
5. Import the certificates you received from the JCA Code Signing Certification Authority into
your keystore with the keytool command.
First import the CA's certificate as a "trusted certificate":
<alias> is the same alias as that which you created in Step 1 where you generated a RSA
keypair. This command replaces the self-signed certificate in the keystore entry specified
by <alias> with the one signed by the JCA Code Signing Certification Authority.
Now that you have in your keystore a certificate from an entity trusted by JCA (the JCA Code
Signing Certification Authority), you can place your provider code in a JAR file (Step 6: Place
Your Provider in a JAR File) and then use that certificate to sign the JAR file (Step 7.2: Sign
Your Provider).
Here, <alias> is the alias into the keystore for the entry containing the code-signing certificate
received from the JCA Code Signing Certification Authority (the same alias as that specified in
the commands in Step 7.1: Get a Code-Signing Certificate).
You can test verification of the signature via the following:
The text "jar verified" will be displayed if the verification was successful.
Note
• You can also use the [Link] API to sign JAR files.
• If you include a signed JCE provider with your application and also want the JAR
file signed for implementing other code-signing policies, you need to apply multiple
signatures to the JCE provider JAR using the appropriate certificates/keys. The
JCE signature is for acceptance of the provider JAR by the JCA framework, the
other signature(s) can be used for making policy decisions. See jarsigner in Java
Platform, Standard Edition Tools Reference for applying multiple signatures to a
JAR file.
• You cannot package signed providers in JMOD files.
• Only providers that supply instances of Cipher, KeyAgreement, KeyGenerator,
Mac, or SecretKFactory must be signed. If your provider only supplies instances of
SecureRandom, MessageDigest, Signature, KeyStore, etc., the provider does not
need to be signed.
• You can link a provider in a custom runtime image with the jlink command as
long as it doesn't have a Cipher, KeyAgreement, KeyGenerator, or MAC
implementation.
[Link].1=SUN
[Link].2=SunRsaSign
[Link].3=SunEC
[Link].4=SunJSSE
[Link].5=SunJCE
[Link].6=SunJGSS
[Link].7=SunSASL
[Link].8=XMLDSig
[Link].9=SunPCSC
[Link].10=JdkLDAP
[Link].11=JdkSASL
[Link].12=SunMSCAPI
[Link].13=SunPKCS11
[Link].n=provName|className
This declares a provider, and specifies its preference order n. The preference order is the
order in which providers are searched for requested algorithms when no specific provider
is requested. The order is 1-based; 1 is the most preferred, followed by 2, and so on.
provName is the provider's name and className is the fully qualified class name of the
provider. You can use either of these two names.
3. Register your provider by adding to the [Link] file a line with the form
[Link].n=provName|className.
If you configured your provider so that the ServiceLoader class can search for it
(because you packaged the provider in a named module as described in Step 4: Create a
Module Declaration for Your Provider or added a [Link] file as
described in Add the File [Link] to Use the ServiceLoader Class to Search
for Providers), then specify just the provider's name.
If you have not configured your provider so that ServiceLoader class can search for it,
which means that the JCA framework will search for it in the class path or module path,
then specify the fully qualified class name of your provider.
For example, the highlighted line registers the provider MyProvider (whose fully qualified
class name is [Link] and has been configured so that the ServiceLoader class
can search for it) as the 14th preferred provider:
# ...
[Link].11=JdkSASL
[Link].12=SunMSCAPI
[Link].13=SunPKCS11
[Link].14=MyProvider
If you are not sure if the ServiceLoader mechanism will be used, or if you'll be deploying
on a non-modular system, then you can also register the provider again, this time using the
full class name:
[Link].15=[Link]
Note
Properties in the [Link] file are typically parsed only once. If you have
modified any property in this file, restart your applications to ensure that the
changes are properly reflected.
Alternatively, you can register providers dynamically. To do so, a program (such as your test
program, to be written in Step 9: Write and Compile Your Test Programs) call either the
addProvider or insertProviderAt method in the Security class:
ServiceLoader<Provider> sl = [Link]([Link]);
for (Provider p : sl) {
[Link](p);
if ([Link]().equals("MyProvider")) {
[Link](p);
}
}
Grant the program, which calls the addProvider or insertProviderAt method, one of the
following permissions:
For example, if the provider name is MyJCE, your program is in the [Link] file in
the /localWork directory, and your program calls the addProvider method, then the
following is a sample policy file that contains a grant statement that grants that permission:
Provider p = [Link]("MyPro");
[Link]("MyPro provider name is " + [Link]());
[Link]("MyPro provider version # is " + [Link]());
[Link]("MyPro provider info is " + [Link]());
3. Optional: If you don't specify a provider name in the call to getInstance, all registered
providers will be searched, in preference order (see Step 8.1: Configure the Provider), until
one implementing the algorithm is found.
4. Optional: If your provider implements an exemption mechanism, you should write a test
application that uses the exemption mechanism. Such an application also needs to be
signed and have a "permission policy file" bundled with it.
See How to Make Applications Exempt from Cryptographic Restrictions for complete
information on creating and testing such an application.
If you packaged your provider as a named module and have configured it so that the
ServiceLoader class can search for it (by registering it with its name in the [Link]
as described in Step 8.1: Configure the Provider), then run your test program with the following
command:
You may require more options depending on your provider code style (see Step 3.1: Create a
Provider That Uses String Objects to Register Its Services and Step 3.2: Create a Provider
That Uses [Link]), if you packaged your provider in a different kind of module, or if
you have not configured it for the ServiceLoader class. The following table describes these
options.
For the java commands, the name of the provider is MyProvider, its fully qualified class name
is [Link], and it is packaged in the file [Link], which is in the
directory jars.
Table 3-2 Expected Java Runtime Options for Various Provider Implementation Styles
Table 3-2 (Cont.) Expected Java Runtime Options for Various Provider Implementation Styles
Once you have determined the proper java options for your test programs, run them. Debug
your code and continue testing as needed. If the Java runtime cannot seem to find one of your
algorithms, review the previous steps and ensure that they are all completed.
Be sure to include testing of your programs using different installation options (for example,
configured to use the ServiceLoader class or to be found in the class path or module path)
and execution environments (with or without a security manager running).
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
1. Optional: If you find during testing that your code needs modification, make the changes
and recompile Step 5: Compile Your Code.
2. Place the updated provider code in a JAR file (Step 6: Place Your Provider in a JAR File).
3. Sign the JAR file (Step 7: Sign Your JAR File, If Necessary).
4. Re-configure the provider (Step 8.1: Configure the Provider).
5. Optional: If needed, fix or add to the permissions (Step 8.2: Set Provider Permissions).
Note
If your provider calls [Link]() and the returned Cipher object needs to
perform strong cryptography regardless of what cryptographic strength is allowed by
the user's downloaded jurisdiction policy files, you should include a copy of the
cryptoPerms permission policy file which you intend to bundle in the JAR file for your
provider and which specifies an appropriate permission for the required cryptographic
strength. The necessity for this file is just like the requirement that applications
"exempt" from cryptographic restrictions must include a cryptoPerms permission policy
file in their JAR file. See How to Make Applications Exempt from Cryptographic
Restrictions.
Note
As of this writing, provider name searches are case-sensitive. That is, if your
master class specifies your provider name as "CryptoX" but a user requests
"CRYPTOx", your provider will not be found. This behavior may change in the
future, but for now be sure to warn your clients to use the exact case you specify.
Step 12.1: Indicate Whether Your Implementation is Cloneable for Message Digests
and MACs
For each Message Digest and MAC algorithm, indicate whether or not your implementation is
cloneable. This is not technically necessary, but it may save clients some time and coding by
telling them whether or not intermediate Message Digests or MACs may be possible through
cloning.
Clients who do not know whether or not a MessageDigest or Mac implementation is cloneable
can find out by attempting to clone the object and catching the potential exception, as
illustrated by the following example:
try {
// try and clone it
/* compute the MAC for i1 */
[Link](i1);
byte[] i1Mac = [Link]().doFinal();
Where,
mac
Indicates the MAC object they received when they requested one via a call to
[Link]
i1, i2 and i3
Indicates input byte arrays, and they want to calculate separate hashes for:
• i1
• i1 and i2
• i1, i2, and i3
Key Factories
A provider should document all the key specifications supported by its (secret-)key factory.
Signature Algorithms
If you implement a signature algorithm, you should document the format in which the signature
(generated by one of the sign methods) is encoded.
For example, the SHA256withDSA signature algorithm supplied by the "SUN" provider
encodes the signature as a standard ASN.1 SEQUENCE of two integers, r and s.
Certificate Factories
A provider should document what types of certificates (and their version numbers, if relevant),
can be created by the factory.
Keystores
A provider should document any relevant information regarding the keystore implementation,
such as its underlying data format.
Step 13: Make Your Class Files and Documentation Available to Clients
After writing, configuring, testing, installing and documenting your provider software, make
documentation available to your customers.
Alias Names
In the JDK, the aliasing scheme enables clients to use aliases when referring to algorithms or
types, rather than the standard names.
For many cryptographic algorithms and types, there is a single official "standard name" defined
in the Java Security Standard Algorithm Names.
For example, "SHA-256" is the standard name for the SHA-256 Message Digest algorithm
defined in FIPS PUB 180-4: Secure Hash Standard (SHS). DiffieHellman is the standard for
the Diffie-Hellman key agreement algorithm defined in PKCS#3.
In the JDK, there is an aliasing scheme that enables clients to use aliases when referring to
algorithms or types, rather than their standard names.
For example, the "SUN" provider's master class ([Link]) defines the alias "SHA1/DSA" for
the algorithm whose standard name is "SHA1withDSA". Thus, the following statements are
equivalent:
Aliases can be defined in your "master class" (see Step 3: Write Your Master Class, a
Subclass of Provider). To define an alias, create a property named
[Link]
where engineClassName is the name of an engine class (e.g., Signature), and aliasName is
your alias name. The value of the property must be the standard algorithm (or type) name for
the algorithm (or type) being aliased.
As an example, the "SUN" provider defines the alias "SHA1/DSA" for the signature algorithm
whose standard name is "SHA1withDSA" by setting a property named
[Link].SHA1/DSA to have the value SHA1withDSA via the following:
put("[Link].SHA1/DSA", "SHA1withDSA");
Note
The aliases defined by one provider are available only to that provider and not to any
other providers. Thus, aliases defined by the SunJCE provider are available only to
the SunJCE provider.
Service Interdependencies
Some algorithms require the use of other types of algorithms. For example, a PBE algorithm
usually needs to use a message digest algorithm in order to transform a password into a key.
If you are implementing one type of algorithm that requires another, you can do one of the
following:
• Provide your own implementations for both.
• Let your implementation of one algorithm use an instance of the other type of algorithm, as
supplied by the default Sun provider that is included with every Java SE Platform
installation. For example, if you are implementing a PBE algorithm that requires a message
digest algorithm, you can obtain an instance of a class implementing the SHA-256
message digest algorithm by calling:
[Link]("SHA-256", "SUN")
• Let your implementation of one algorithm use an instance of the other type of algorithm, as
supplied by another specific provider. This is only appropriate if you are sure that all clients
who will use your provider will also have the other provider installed.
• Let your implementation of one algorithm use an instance of the other type of algorithm, as
supplied by another (unspecified) provider. That is, you can request an algorithm by name,
but without specifying any particular provider, as in:
[Link]("SHA-256")
This is only appropriate if you are sure that there will be at least one implementation of the
requested algorithm (in this case, SHA-256) installed on each Java platform where your
provider will be used.
Here are some common types of algorithm interdependencies:
Default Initialization
In case the client does not explicitly initialize a key pair generator or an algorithm parameter
generator, each provider of such a service must supply (and document) a default initialization.
SUNJDK Providers Documentation
KeyPair kp = [Link]();
This example prints output similar to the following (line breaks and spaces have been added
for clarity):
They have default implementations, but can be overridden by providers if needed, as may be
the case with providers that interface with hardware security tokens.
The newInstance() method is used by the security framework when it needs to construct new
implementation instances. The default implementation uses reflection to invoke the standard
constructor for the respective type of service. For all standard services except CertStore, this
is the no-args constructor. The constructorParameter to newInstance() must be null in
theses cases. For services of type CertStore, the constructor that takes a
CertStoreParameters object is invoked, and constructorParameter must be a non-null
instance of CertStoreParameters. A security provider can override the newInstance()
method to implement instantiation as appropriate for that implementation. It could use direct
invocation or call a constructor that passes additional information specific to the Provider
instance or token. For example, if multiple Smartcard readers are present on the system, it
might pass information about which reader the newly created service is to be associated with.
However, despite customization all implementations must follow the conventions about
constructorParameter described previously.
The supportsParameter() tests whether the Service can use the specified parameter. It
returns false if this service cannot use the parameter. It returns true if this service can use the
parameter, if a fast test is infeasible, or if the status is unknown. It is used by the security
framework with some types of services to quickly exclude non-matching implementations from
consideration. It is currently only defined for the following standard services: Signature,
Cipher, Mac, and KeyAgreement. The parameter must be an instance of Key in these cases. For
example, for Signature services, the framework tests whether the service can use the supplied
Key before instantiating the service. The default implementation examines the attributes
SupportedKeyFormats and SupportedKeyClasses. Again, a provider may override this methods
to implement additional tests.
The SupportedKeyFormats attribute is a list of the supported formats for encoded keys (as
returned by [Link]()) separated by the "|" (pipe) character. For example, X.509|
PKCS#8. The SupportedKeyClasses attribute is a list of the names of classes of interfaces
separated by the "|" character. A key object is considered to be acceptable if it is assignable to
at least one of those classes or interfaces named. In other words, if the class of the key object
is a subclass of one of the listed classes (or the class itself) or if it implements the listed
interface. An example value is "[Link]|
[Link]" .
Four methods have been added to the Provider class for adding and looking up Services. As
mentioned earlier, the implementation of those methods and also of the existing Properties
methods have been specifically designed to ensure compatibility with existing Provider
subclasses. This is achieved as follows:
If legacy Properties methods are used to add entries, the Provider class makes sure that the
property strings are parsed into equivalent Service objects prior to lookup via getService().
Similarly, if the putService() method is used, equivalent property strings are placed into the
provider's hashtable at the same time. If a provider implementation overrides any of the
methods in the Provider class, it has to ensure that its implementation does not interfere with
this conversion. To avoid problems, we recommend that implementations do not override any
of the methods in the Provider class.
Signature Formats
The signature algorithm should specify the format in which the signature is encoded.
If you implement a signature algorithm, the documentation you supply (Step 12: Document
Your Provider and Its Supported Services) should specify the format in which the signature
(generated by one of the sign methods) is encoded.
For example, the SHA1withDSA signature algorithm supplied by the Sun provider encodes the
signature as a standard ASN.1 sequence of two ASN.1 INTEGER values: r and s, in that order:
SEQUENCE ::= {
r INTEGER,
s INTEGER }
DSAKeyPairGenerator
The interface DSAKeyPairGenerator is obsolete. It used to be needed to enable clients to
provide DSA-specific parameters to be used rather than the default parameters your
implementation supplies. However, it's no longer necessary. The
[Link] method that takes an AlgorithmParameterSpec
parameter enables clients to indicate algorithm-specific parameters.
DSAParams Implementation
If you are implementing a DSA key pair generator, you need a class implementing DSAParams
for holding and returning the p, q, and g parameters.
Note
There is a DSAParams implementation built into the JDK: the
[Link] class.
If you implement a DSA key pair generator, your generateKeyPair method (in your
KeyPairGeneratorSpi subclass) will return instances of your implementations of those
interfaces.
If you implement a DSA key factory, your engineGeneratePrivate method (in your
KeyFactorySpi subclass) will return an instance of your DSAPrivateKey implementation,
and your engineGeneratePublic method will return an instance of your DSAPublicKey
implementation.
Also, your engineGetKeySpec and engineTranslateKey methods will expect the passed-
in key to be an instance of a DSAPrivateKey or DSAPublicKey implementation. The
getParams method provided by the interface implementations is useful for obtaining and
extracting the parameters from the keys and then using the parameters, for example as
parameters to the DSAParameterSpec constructor called to create a parameter specification
from parameter values that could be used to initialize a KeyPairGenerator object for DSA.
If you implement a DSA signature algorithm, your engineInitSign method (in your
SignatureSpi subclass) will expect to be passed a DSAPrivateKey and your
engineInitVerify method will expect to be passed a DSAPublicKey.
Please note: The DSAPublicKey and DSAPrivateKey interfaces define a very generic,
provider-independent interface to DSA public and private keys, respectively. The
engineGetKeySpec and engineTranslateKey methods (in your KeyFactorySpi
subclass) could additionally check if the passed-in key is actually an instance of their provider's
own implementation of DSAPrivateKey or DSAPublicKey, for example, to take advantage
of provider-specific implementation details. The same is true for the DSA signature algorithm
engineInitSign and engineInitVerify methods (in your SignatureSpi subclass).
To see what methods need to be implemented by classes that implement the DSAPublicKey
and DSAPrivateKey interfaces, first note the following interface signatures:
To implement the DSAPrivateKey and DSAPublicKey interfaces, you must implement the
methods they define as well as those defined by interfaces they extend, directly or indirectly.
Thus, for private keys, you need to supply a class that implements:
• The getX method from the DSAPrivateKey interface.
• The getParams method from the DSAKey interface because DSAPrivateKey extends
DSAKey.
Note
The getParams method returns a DSAParams object, so you must also have a
DSAParams implementation.
• The getAlgorithm, getEncoded, and getFormat methods from the Key interface
because DSAPrivateKey extends [Link], and PrivateKey
extends Key.
Similarly, for public DSA keys, you need to supply a class that implements:
• The getY method from the DSAPublicKey interface.
• The getParams method from the DSAKey interface because DSAPublicKey extends
DSAKey.
Note
The getParams method returns a DSAParams object, so you must also have a
DSAParams implementation.
• The getAlgorithm, getEncoded, and getFormat methods from the Key interface
because DSAPublicKey extends [Link], and PublicKey
extends Key.
Also, your engineGetKeySpec and engineTranslateKey methods will expect the passed-in key
to be an instance of an RSAPrivateKey, RSAPrivateCrtKey, or RSAPublicKey implementation.
If you implement an RSA signature algorithm, your engineInitSign method (in your
SignatureSpi subclass) will expect to be passed either an RSAPrivateKey or an
RSAPrivateCrtKey, and your engineInitVerify method will expect to be passed an
RSAPublicKey.
To see what methods need to be implemented by classes that implement the RSAPublicKey,
RSAPrivateKey, and RSAPrivateCrtKey interfaces, first note the following interface signatures:
• DHPublicKey
• DHKey
• DHPrivateKey
The following sections discuss requirements for implementations of these interfaces.
If you implement a Diffie-Hellman key pair generator, your generateKeyPair method (in your
KeyPairGeneratorSpi subclass) will return instances of your implementations of those
interfaces.
If you implement a Diffie-Hellman key factory, your engineGeneratePrivate method (in your
KeyFactorySpi subclass) will return an instance of your DHPrivateKey implementation, and
your engineGeneratePublic method will return an instance of your DHPublicKey
implementation.
Also, your engineGetKeySpec and engineTranslateKey methods will expect the passed-in key
to be an instance of a DHPrivateKey or DHPublicKey implementation. The getParams method
provided by the interface implementations is useful for obtaining and extracting the parameters
from the keys. You can then use the parameters, for example, as parameters to the
DHParameterSpec constructor called to create a parameter specification from parameter values
used to initialize a KeyPairGenerator object for Diffie-Hellman.
If you implement the Diffie-Hellman key agreement algorithm, your engineInit method (in your
KeyAgreementSpi subclass) will expect to be passed a DHPrivateKey and your engineDoPhase
method will expect to be passed a DHPublicKey.
Note
The DHPublicKey and DHPrivateKey interfaces define a very generic, provider-
independent interface to Diffie-Hellman public and private keys, respectively. The
engineGetKeySpec and engineTranslateKey methods (in your KeyFactorySpi
subclass) could additionally check if the passed-in key is actually an instance of their
provider's own implementation of DHPrivateKey or DHPublicKey, for example, to take
advantage of provider-specific implementation details. The same is true for the Diffie-
Hellman algorithm engineInit and engineDoPhase methods (in your KeyAgreementSpi
subclass).
To see what methods need to be implemented by classes that implement the DHPublicKey and
DHPrivateKey interfaces, first note the following interface signatures:
To implement the DHPrivateKey and DHPublicKey interfaces, you must implement the methods
they define as well as those defined by interfaces they extend, directly or indirectly.
Thus, for private keys, you need to supply a class that implements:
• The getX method from the DHPrivateKey interface.
• The getParams method from the DHKey interface because DHPrivateKey extends DHKey.
• The getAlgorithm, getEncoded, and getFormat methods from the Key interface because
DHPrivateKey extends [Link], and PrivateKey extends Key.
Similarly, for public Diffie-Hellman keys, you need to supply a class that implements:
• The getY method from the DHPublicKey interface.
• The getParams method from the DHKey interface because DHPublicKey extends DHKey.
• The getAlgorithm, getEncoded, and getFormat methods from the Key interface because
DHPublicKey extends [Link], and PublicKey extends Key.
These methods return the DSA algorithm parameters: the prime p, the sub-prime q, and the
base g.
Many types of DSA services will find this class useful - for example, it is utilized by the DSA
signature, key pair generator, algorithm parameter generator, and algorithm parameters
classes implemented by the Sun provider. As a specific example, an algorithm parameters
implementation must include an implementation for the getParameterSpec method, which
returns an AlgorithmParameterSpec. The DSA algorithm parameters implementation supplied
by Sun returns an instance of the DSAParameterSpec class.
Method Description
byte[] getIV() Returns the initialization vector (IV).
Method Description
String getDigestAlgorithm() Returns the message digest algorithm name.
String getMGFAlgorithm() Returns the mask generation function algorithm
name.
AlgorithmParameterSpec Returns the parameters for the mask generation
getMGFParameters() function.
PSource getPSource() Returns the source of encoding input P.
Method Description
int getIterationCount() Returns the iteration count.
byte[] getSalt() Returns the salt.
Method Description
boolean equals(Object obj) Tests for equality between the specified object and
this object.
int getEffectiveKeyBits() Returns the effective key size in bits.
byte[] getIV() Returns the IV or null if this parameter set does not
contain an IV.
int hashCode() Calculates a hash code value for the object.
Method Description
boolean equals(Object obj) Tests for equality between the specified object and
this object.
Method Description
byte[] getIV() Returns the IV or null if this parameter set does not
contain an IV.
int getRounds() Returns the number of rounds.
int getVersion() Returns the version.
int getWordSize() Returns the word size in bits.
int hashCode() Calculates a hash code value for the object.
Method Description
BigInteger getG() Returns the base generator g.
int getL() Returns the size in bits, l, of the random exponent
(private value).
BigInteger getP() Returns the prime modulus p.
Many types of Diffie-Hellman services will find this class useful; for example, it is used by the
Diffie-Hellman key agreement, key pair generator, algorithm parameter generator, and
algorithm parameters classes implemented by the "SunJCE" provider. As a specific example,
an algorithm parameters implementation must include an implementation for the
getParameterSpec method, which returns an AlgorithmParameterSpec. The Diffie-Hellman
algorithm parameters implementation supplied by "SunJCE" returns an instance of the
DHParameterSpec class.
This is contrasted with an opaque representation, as defined by the Key interface, in which you
have no direct access to the parameter fields. In other words, an "opaque" representation
gives you limited access to the key - just the three methods defined by the Key interface:
getAlgorithm, getFormat, and getEncoded.
Java defines the following key specification interfaces and classes in the [Link]
and [Link] packages:
This interface contains no methods or constants. Its only purpose is to group (and provide type
safety for) all key specifications. All key specifications must implement this interface.
Java supplies several classes implementing the KeySpec interface:
• DSAPrivateKeySpec
• DSAPublicKeySpec
• RSAPrivateKeySpec
• RSAPublicKeySpec
• EncodedKeySpec
• PKCS8EncodedKeySpec
• X509EncodedKeySpec
If your provider uses key types (e.g., Your_PublicKey_type and Your_PrivateKey_type) for
which the JDK does not already provide corresponding KeySpec classes, there are two
possible scenarios, one of which requires that you implement your own key specifications:
1. If your users will never have to access specific key material values of your key type, you
will not have to provide any KeySpec classes for your key type.
In this scenario, your users will always create Your_PublicKey_type and
Your_PrivateKey_type keys through the appropriate KeyPairGenerator supplied by your
provider for that key type. If they want to store the generated keys for later usage, they
retrieve the keys' encodings (using the getEncoded method of the Key interface). When
they want to create an Your_PublicKey_type or Your_PrivateKey_type key from the
encoding (e.g., in order to initialize a Signature object for signing or verification), they
create an instance of X509EncodedKeySpec or PKCS8EncodedKeySpec from the encoding,
and feed it to the appropriate KeyFactory supplied by your provider for that algorithm,
whose generatePublic and generatePrivate methods will return the requested
PublicKey (an instance of Your_PublicKey_type) or PrivateKey (an instance of
Your_PrivateKey_type) object, respectively.
2. If you anticipate a need for users to access specific key material values of your key type, or
to construct a key of your key type from key material and associated parameter values,
rather than from its encoding (as in the previous case), you have to specify new KeySpec
classes (classes that implement the KeySpec interface) with the appropriate constructor
methods and get methods for returning key material fields and associated parameter
values for your key type. You will specify those classes in a similar manner as is done by
the DSAPrivateKeySpec and DSAPublicKeySpec classes. You need to ship those classes
along with your provider classes, for example, as part of your provider JAR file.
These methods return the private key x, and the DSA algorithm parameters used to calculate
the key: the prime p, the sub-prime q, and the base g.
These methods return the RSA modulus n and private exponent d values that constitute the
RSA private key.
These methods return the public exponent e and the CRT information integers: the prime factor
p of the modulus n, the prime factor q of n, the exponent d mod (p-1), the exponent d mod
(q-1), and the Chinese Remainder Theorem coefficient (inverse of q) mod p.
An RSA private key logically consists of only the modulus and the private exponent. The
presence of the CRT values is intended for efficiency.
Its getEncoded method returns the key bytes, encoded according to the X.509 standard. Its
getFormat method returns the string "X.509".DHPrivateKeySpec, DHPublicKeySpec,
DESKeySpec, DESedeKeySpec, PBEKeySpec, and SecretKeySpec.
Secret-Key Generation
If you provide a secret-key generator (subclass of [Link]) for a
particular secret-key algorithm, you may return the generated secret-key object.
The generated secret-key object (which must be an instance of [Link], see
engineGenerateKey) can be returned in one of the following ways:
• You implement a class whose instances represent secret-keys of the algorithm associated
with your key generator. Your key generator implementation returns instances of that class.
This approach is useful if the keys generated by your key generator have provider-specific
properties.
• Your key generator returns an instance of SecretKeySpec, which already implements the
[Link] interface. You pass the (raw) key bytes and the name of the
secret-key algorithm associated with your key generator to the SecretKeySpec constructor.
This approach is useful if the underlying (raw) key bytes can be represented as a byte
array and have no key-parameters associated with them.
put("[Link].<engine_type>.[Link].[Link]",
"<algorithm_alias_name>");
Note that if your algorithm is known under more than one object identifier, you need to create
an alias entry for each object identifier under which it is known.
An example of where the JCA needs to perform this type of mapping is when your algorithm
("Foo") is a signature algorithm and users run the keytool command and specify your
(signature) algorithm alias.
In this case, your provider master file should contain the following entries:
put("[Link]", "[Link]");
put("[Link].[Link].[Link]", "Foo");
Other examples of where this type of mapping is performed are (1) when your algorithm is a
keytype algorithm and your program parses a certificate (using the X.509 implementation of
the SUN provider) and extracts the public key from the certificate in order to initialize a
Signature object for verification, and (2) when keytool users try to access a private key of your
keytype (for example, to perform a digital signature) after having generated the corresponding
keypair. In these cases, your provider master file should contain the following entries:
put("[Link]", "[Link]");
put("[Link].[Link].[Link]", "Foo");
put("[Link].[Link].[Link]", "MySigAlg");
If your algorithm is known under more than one object identifier, prefix the preferred one with
"OID."
An example of where the JCA needs to perform this kind of mapping is when users run
keytool in any mode that takes a -sigalg option. For example, when the -genkeypair and -
certreq commands are invoked, the user can specify your (signature) algorithm with the -
sigalg option.
Ensuring Exportability
A key feature of JCA is the exportability of the JCA framework and of the provider cryptography
implementations if certain conditions are met.
By default, an application can use cryptographic algorithms of any strength. However, due to
import regulations in some countries, you may have to limit those algorithms' strength. You do
this with jurisdiction policy files; see Cryptographic Strength Configuration. The JCA framework
will enforce the restrictions specified in the installed jurisdiction policy files.
As noted elsewhere, you can write just one version of your provider software, implementing
cryptography of maximum strength. It is up to JCA, not your provider, to enforce any
jurisdiction policy file-mandated restrictions regarding the cryptographic algorithms and
maximum cryptographic strengths available to applets/applications in different locations.
The conditions that must be met by your provider in order to enable it to be plugged into JCA
are the following:
• The provider code should be written in such a way that provider classes become unusable
if instantiated by an application directly, bypassing JCA. See Step 1: Write your Service
Implementation Code in Steps to Implement and Integrate a Provider.
• The provider package must be signed by an entity trusted by the JCA framework. (See
Step 7.1: Get a Code-Signing Certificate through Step 7.2: Sign Your Provider.) U.S.
vendors whose providers may be exported outside the U.S. first need to apply for U.S.
government export approval. (See Step 11: Apply for U.S. Government Export Approval If
Required.)
src/[Link]/[Link]
See Step 4: Create a Module Declaration for Your Provider for information about the module
declaration, which is specified in [Link].
module [Link] {
provides [Link] with [Link];
}
src/[Link]/com/example/MyProvider/[Link]
The MyProvider class is an example of a provider that uses the [Link] class.
See Step 3.2: Create a Provider That Uses [Link].
package [Link];
import [Link].*;
import [Link].*;
/**
* Test JCE provider.
*
* Registers services using [Link] and overrides newInstance().
*/
public final class MyProvider extends Provider {
public MyProvider() {
super("MyProvider", "1.0", "My JCE provider");
[Link]((PrivilegedAction<Void>) () -> {
putService(new ProviderService(p, "Cipher",
"MyCipher", "[Link]"));
return null;
});
}
@Override
public Object newInstance(Object ctrParamObj)
throws NoSuchAlgorithmException {
@Override
public String toString() {
return "MyProvider [getName()=" + getName()
+ ", getVersionStr()=" + getVersionStr() + ", getInfo()="
+ getInfo() + "]";
}
}
src/[Link]/com/example/MyProvider/[Link]
The MyCipher class extends the CipherSPI, which is a Server Provider Interface (SPI).
Each cryptographic service that a provider implements has a subclass of the appropriate SPI.
See Step 1: Write your Service Implementation Code.
Note
This code is only a stub provider that demonstrates how to write a provider; it's
missing the actual cryptographic algorithm implementation. The MyCipher class would
contain an actual cryptographic algorithm implementation if MyProvider were a real
security provider.
package [Link];
import [Link].*;
import [Link].*;
import [Link].*;
/**
* Implementation represents a test Cipher.
*
* All are stubs.
*/
public class MyCipher extends CipherSpi {
@Override
protected byte[] engineDoFinal(byte[] input, int inputOffset, int
inputLen)
throws IllegalBlockSizeException, BadPaddingException {
return null;
}
@Override
protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException,
IllegalBlockSizeException, BadPaddingException {
return 0;
}
@Override
protected int engineGetBlockSize() {
return 0;
}
@Override
protected byte[] engineGetIV() {
return null;
}
@Override
protected int engineGetOutputSize(int inputLen) {
return 0;
}
@Override
protected AlgorithmParameters engineGetParameters() {
return null;
}
@Override
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
}
@Override
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
}
@Override
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
SecureRandom random) throws InvalidKeyException,
InvalidAlgorithmParameterException {
}
@Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException
{
}
@Override
protected void engineSetPadding(String padding)
throws NoSuchPaddingException {
}
@Override
protected int engineGetKeySize(Key key)
throws InvalidKeyException {
return 0;
}
@Override
protected byte[] engineUpdate(byte[] input, int inputOffset, int
inputLen) {
return null;
}
@Override
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException {
return 0;
}
}
src/[Link]/META-INF/services/[Link]
The [Link] file enables automatic or unnamed modules to use the
ServiceLoader class to search for your providers. See Step 6: Place Your Provider in a JAR
File.
[Link]
src/[Link]/[Link]
This file contains a uses directive, which specifies a service that the module requires. This
directive helps the module system locate providers and ensure that they run reliably. This is the
complement to the provides directive in the MyProvider module definition.
module [Link] {
uses [Link];
}
src/[Link]/com/example/MyApp/[Link]
package [Link];
import [Link].*;
import [Link].*;
import [Link].*;
/**
* A simple JCE test client to access a simple test Provider/Cipher
* implementation in a signed modular jar.
*/
public class MyApp {
/*
* Registers MyProvider dynamically.
*
* Could do statically by editing the [Link] file.
* Use the first form if using ServiceLoader ("uses" or
* META-INF/service), the second if using the traditional class
* lookup method. Both if provider could be deployed to either.
*
* [Link].14=MyProvider
* [Link].15=[Link]
*/
ServiceLoader<Provider> sl =
[Link]([Link]);
for (Provider p : sl) {
if ([Link]().equals(PROVIDER)) {
[Link]("Registering the Provider");
[Link](p);
}
}
/*
* Get a MyCipher from MyProvider and initialize it.
*/
Cipher cipher = [Link](CIPHER, PROVIDER);
[Link](Cipher.ENCRYPT_MODE, (Key) null);
/*
* What Provider did we get?
*/
Provider p = [Link]();
Class c = [Link]();
Module m = [Link]();
[Link]([Link]() + ": version "
+ [Link]() + "\n"
+ [Link]() + "\n "
+ (([Link]() == null) ? "<UNNAMED>" : [Link]())
+ "/" + [Link]());
}
}
[Link]
#!/bin/sh
#
# A simple example to show how a JCE provider could be developed in a
# modular JDK, for deployment as either Named/Unnamed modules.
#
#
# Edit as appropriate
#
JDK_DIR=d:/java/jdk9
KEYSTORE=YourKeyStore
STOREPASS=YourStorePass
SIGNER=YourAlias
echo "-----------"
echo "Clean/Init"
echo "-----------"
rm -rf mods jars
mkdir mods jars
echo "--------------------"
echo "Compiling MyProvider"
echo "--------------------"
${JDK_DIR}/bin/[Link] \
--module-source-path src \
-d mods \
$(find src/[Link] -name '*.java' -print)
echo "------------------------------------"
echo "Packaging [Link]"
echo "------------------------------------"
${JDK_DIR}/bin/[Link] --create \
--file jars/[Link] \
--verbose \
--module-version=1.0 \
-C mods/[Link] . \
-C src/[Link] META-INF/services
echo "----------------------------------"
echo "Signing [Link]"
echo "----------------------------------"
${JDK_DIR}/bin/[Link] \
-keystore ${KEYSTORE} \
-storepass ${STOREPASS} \
jars/[Link] ${SIGNER}
echo "---------------"
echo "Compiling MyApp"
echo "---------------"
${JDK_DIR}/bin/[Link] \
--module-source-path src \
-d mods \
$(find src/[Link] -name '*.java' -print)
echo "-------------------------------"
echo "Packaging [Link]"
echo "-------------------------------"
${JDK_DIR}/bin/[Link] --create \
--file jars/[Link] \
--verbose \
--module-version=1.0 \
-C mods/[Link] .
echo "------------------------"
echo "Test1 "
echo "Named Provider/Named App"
echo "------------------------"
${JDK_DIR}/bin/[Link] \
--module-path 'jars' \
-m [Link]/[Link]
echo "--------------------------"
echo "Test2 "
echo "Named Provider/Unnamed App"
echo "--------------------------"
${JDK_DIR}/bin/[Link] \
--module-path 'jars/[Link]' \
--class-path 'jars/[Link]' \
[Link]
echo "--------------------------"
echo "Test3 "
echo "Unnamed Provider/Named App"
echo "--------------------------"
${JDK_DIR}/bin/[Link] \
--module-path 'jars/[Link]' \
--class-path 'jars/[Link]' \
-m [Link]/[Link]
echo "----------------------------"
echo "Test4 "
echo "Unnamed Provider/Unnamed App"
echo "----------------------------"
${JDK_DIR}/bin/[Link] \
--class-path \
'jars/[Link];jars/[Link]' \
[Link]
Note
The Java Security Standard Algorithm Names contains more information about the
standard names used in this document.
Topics
Introduction to JDK Providers
Import Limits on Cryptographic Algorithms
Cipher Transformations
SecureRandom Implementations
The SunPKCS11 Provider
The SUN Provider
The SunRsaSign Provider
The SunJSSE Provider
The SunJCE Provider
The SunJGSS Provider
The SunSASL Provider
The XMLDSig Provider
The SunPCSC Provider
The SunMSCAPI Provider
The SunEC Provider
The OracleUcrypto Provider
The Apple Provider
The JdkLDAP Provider
The JdkSASL Provider
versus
getInstance("..."); // recommended
Otherwise, applications are tied to specific providers that may not be available on other Java
implementations. They also might not be able to take advantage of available optimized
providers (for example, hardware accelerators via PKCS11 or native OS implementations such
as Microsoft's MSCAPI) that have a higher preference order than the specific requested
provider.
The following table lists the modules and the supported Java Cryptographic Service Providers:
Module Provider(s)
[Link] SUN, SunRsaSign, SunJSSE, SunJCE, Apple
[Link] JdkLDAP
[Link] SunJGSS
[Link] SunSASL
[Link] SunPCSC
[Link] XMLDSig
[Link] SunPKCS11
[Link] SunEC
[Link] SunMSCAPI
[Link] JdkSASL
Cipher Transformations
The [Link](String transformation) factory method generates
Cipher objects using transformations of the form algorithm/mode/padding. If the mode/
padding are omitted, the SunJCE and SunPKCS11 providers use ECB as the default mode
and PKCS5Padding as the default padding for many symmetric ciphers.
It is recommended to use transformations that fully specify the algorithm, mode, and padding
instead of relying on the defaults. The defaults are provider specific and can vary among
providers.
Note
ECB mode is the easiest block cipher mode to use and is the default cipher mode.
ECB works well for single blocks of data and can be parallelized but generally should
not be used for encrypting multiple data blocks due to characteristics of the mode.
This could result in trivial and full disclosure of confidential data. While this mode is
available for use, it should only be used with an understanding of the cryptographic
risks involved.
SecureRandom Implementations
The following table lists the default preference order of the available SecureRandom
implementations.
1 The SunPKCS11 provider is available on all platforms, but is only enabled by default on Solaris as it is the only OS
with a native PKCS11 implementation automatically installed and configured. On other platforms, applications or
deployers must specifically install and configure a native PKCS11 library, and then configure and enable the
SunPKCS11 provider to use it.
2
The PKCS11 SecureRandom implementation for Solaris has been disabled due to the performance overhead of
small-sized requests (see JDK-8098581: [Link]() hurts performance with small size requests).
Edit [Link] to reenable.
3
On Solaris, Linux, and OS X, if the entropy gathering device in [Link] is set to file:/dev/urandom
or file:/dev/random, then NativePRNG is preferred to SHA1PRNG. Otherwise, SHA1PRNG is preferred.
4 There is currently no NativePRNG on Windows. Access to the equivalent functionality is via the SunMSCAPI
provider.
Note
For signature
generation, if the
security strength of the
digest algorithm is
weaker than the
security strength of the
key used to sign the
signature (for example,
using (2048, 256)-bit
DSA keys with the
SHA1withDSA
signature), then the
operation will fail with
the error message:
"The security strength
of SHA1 digest
algorithm is not
sufficient for this key
size."
1
The PKCS12 KeyStore implementation does not support the KeyBag type.
Keysize Restrictions
The SUN provider uses the following default keysizes (in bits) and enforces the following
restrictions:
CertificateFactory/CertPathBuilder/CertPathValidator/CertStore Implementations
See Appendix B: CertPath Implementation in SUN Provider in the Java PKI Programmer's
Guide Additional for details of the SUN provider implementations for CertificateFactory,
CertPathBuilder, CertPathValidator, and CertStore.
Keysize Restrictions
The SunRsaSign provider uses the following default keysize (in bits) and enforces the following
restriction:
SSLv3 No No
TLS Yes Yes
TLSv11 No No
TLSv1.11 No No
TLSv1.2 Yes Yes
TLSv1.3 Yes Yes
SSLv2Hello No Yes
DTLS Yes Yes
DTLSv1.0 Yes Yes
DTLSv1.2 Yes Yes
1 TLS 1.0 and 1.1 are versions of the TLS protocol that are no longer considered secure and have been superseded
by more secure and modern versions (TLS 1.2 and 1.3). These versions have now been disabled by default. If you
encounter issues, you can, at your own risk, re-enable the versions by removing TLSv1 or TLSv1.1 from the
[Link] Security Property in the [Link] configuration file.
Note
The protocols available by default in a JDK release change as new protocols are
developed and old protocols are found to be less effective than previously thought.
The JDK uses two mechanisms to restrict the availability of these protocols:
• The [Link] Security Property: This disables categories of
protocols and cipher suites. For example, if this Security Property contains SSLv3,
then the SSLv3 protocol would be disabled. See Disabled and Restricted
Cryptographic Algorithms for information about this Security Property.
• Moving the protocol to the list of protocols not enabled by default as indicated in
Table 4-12.
• TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
• TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
• TLS_RSA_WITH_AES_256_CBC_SHA
• TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
• TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
• TLS_DHE_RSA_WITH_AES_256_CBC_SHA
• TLS_DHE_DSS_WITH_AES_256_CBC_SHA
• TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
• TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
• TLS_RSA_WITH_AES_128_CBC_SHA256
• TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
• TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
• TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
• TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
• TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
• TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
• TLS_RSA_WITH_AES_128_CBC_SHA
• TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
• TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
• TLS_DHE_RSA_WITH_AES_128_CBC_SHA
• TLS_DHE_DSS_WITH_AES_128_CBC_SHA
• TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
• TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
• SSL_RSA_WITH_3DES_EDE_CBC_SHA
• TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
• TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
• SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
• SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
• TLS_EMPTY_RENEGOTIATION_INFO_SCSV
• TLS_DH_anon_WITH_AES_256_GCM_SHA384
• TLS_DH_anon_WITH_AES_128_GCM_SHA256
• TLS_DH_anon_WITH_AES_256_CBC_SHA256
• TLS_ECDH_anon_WITH_AES_256_CBC_SHA
• TLS_DH_anon_WITH_AES_256_CBC_SHA
• TLS_DH_anon_WITH_AES_128_CBC_SHA256
• TLS_ECDH_anon_WITH_AES_128_CBC_SHA
• TLS_DH_anon_WITH_AES_128_CBC_SHA
• TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA
• SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
• TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
• TLS_ECDHE_RSA_WITH_RC4_128_SHA
• SSL_RSA_WITH_RC4_128_SHA
• TLS_ECDH_ECDSA_WITH_RC4_128_SHA
• TLS_ECDH_RSA_WITH_RC4_128_SHA
• SSL_RSA_WITH_RC4_128_MD5
• TLS_ECDH_anon_WITH_RC4_128_SHA
• SSL_DH_anon_WITH_RC4_128_MD5
• SSL_RSA_WITH_DES_CBC_SHA
• SSL_DHE_RSA_WITH_DES_CBC_SHA
• SSL_DHE_DSS_WITH_DES_CBC_SHA
• SSL_DH_anon_WITH_DES_CBC_SHA
• SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
• SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
• SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
• SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA
• SSL_RSA_EXPORT_WITH_RC4_40_MD5
• SSL_DH_anon_EXPORT_WITH_RC4_40_MD5
• TLS_RSA_WITH_NULL_SHA256
• TLS_ECDHE_ECDSA_WITH_NULL_SHA
• TLS_ECDHE_RSA_WITH_NULL_SHA
• SSL_RSA_WITH_NULL_SHA
• TLS_ECDH_ECDSA_WITH_NULL_SHA
• TLS_ECDH_RSA_WITH_NULL_SHA
• TLS_ECDH_anon_WITH_NULL_SHA
• SSL_RSA_WITH_NULL_MD5
Note
• The cipher suite order of preference may change in future releases.
• TLS_EMPTY_RENEGOTIATION_INFO_SCSV is a pseudo-cipher suite that
supports RFC 5746.
The cipher suites available by default in a JDK release change as new algorithms are
developed and old algorithms are found to be less effective than previously thought. Oracle
JDK uses two mechanisms to restrict the availability of these algorithms:
• The [Link] Security Property, which disables categories of cipher
suites. For example, if this Security Property contains RC4, then all RC4-based cipher
suites would be disabled.
• Moving the cipher suite to the list of suites not enabled by default.
See Disabled and Restricted Cryptographic Algorithms for information about the
[Link] Security Property.
import [Link].*;
import [Link].*;
import [Link].*;
[Link]();
Alternatively, to obtain the current list of protocols and cipher suites that are available by
default, run the following command:
java -XshowSettings:security:tls
Note that the list generated by these commands don't include suites that the
[Link] Security Property disabled.
Table 4-13 (Cont.) SunJCE Provider Algorithm Names for Engine Classes
Table 4-13 (Cont.) SunJCE Provider Algorithm Names for Engine Classes
Cipher Transformations
The following table lists cipher transformations available in the SunJCE provider.
1 CFB/OFB with no specified value defaults to the block size of the algorithm. (for example, AES is 128; Blowfish, DES, DESede, and RC2
are 64.)
2 Though the standard doesn't specify or require the padding bytes to be random, the Java SE ISO10126Padding implementation pads with
random bytes (until the last byte, which provides the length of padding, as specified).
3 PBEWithMD5AndTripleDES is a proprietary algorithm that has not been standardized.
Keysize Restrictions
The SunJCE provider uses the following default keysizes (in bits) and enforces the following
restrictions:
Note
The various Password-Based Encryption (PBE) algorithms use various algorithms to
generate key data, and ultimately depends on the targeted Cipher algorithm. For
example,
”PBEWithMD5AndDES” will always generate 56–bit keys.
OID Name
1.2.840.113554.1.2.2 Kerberos v5
[Link].5.5.2 SPNEGO
Algorithms
The following algorithms are available in the SunPCSC provider:
Table 4-21 The SunPCSC Provider Algorithm Names for Engine Classes
Algorithms
The following algorithms are available in the SunMSCAPI provider:
Keysize Restrictions
The SunMSCAPI provider uses the following default keysizes (in bits) and enforce the
following restrictions:
KeyGenerator
Algorithms
The following algorithms are available in the SunEC provider:
1
This algorithm won't be available from the SunEC provider through the JCA/JCE APIs if you delete the SunEC
provider's native library. See Effect of Removing SunEC Provider's Native Library.
Note
• The XDH algorithm can be initialized with either X25519 or X448 parameters and
keys.
• The X25519 algorithm supports X25519 parameters and keys only. Similarly, the
X448 algorithm supports X448 parameters and keys only.
Note
Other installed providers (for example, SunPCKS11) may still provide these algorithms.
Libraries and tools (for example, JSSE, XML Digital Signature, and keytool) that use these
algorithms may have reduced functionality. For example, JSSE may no longer be able to
generate EC keypairs, use EC-based peer certificates, or perform ECDH/ECDHE key
agreements for SSL/TLS/DTLS connections. Ciphersuites such as TLS_*_ECDSA and
TLS_ECDHE_* may be unavailable. SSL/TLS connections can still use alternate algorithms to
secure connections, such as RSA-/DSA-based certificates and key agreements based on
DH/DHE (RFC 2631), FFDHE (RFC 7919), or XDH/x25519/x448 (RFC 7748).
Even if the native library is removed, the rest of the algorithms (the algorithms without a
footnote) are still available from the SunEC provider, as they are not implemented in the native
library code.
Keysize Restrictions
The SunEC provider uses the following default keysizes (in bits) and enforces the following
restrictions:
Recommended Curves
The following table lists the elliptic curves that are provided by the SunEC provider and are
implemented using modern formulas and techniques. These curves are recommended and
should be preferred over the curves listed in the section Legacy Curves Retained for
Compatibility.
Note
It is recommended that you migrate to newer curves.
The following table lists elliptic curves that are provided by the SunEC provider and are not
implemented using modern formulas and techniques. These curves remain available for
compatibility reasons to afford legacy systems time to migrate to newer curves. These
implementations will be removed or replaced in a future version of the JDK.
Table 4-27 (Cont.) SunEC Provider Legacy Curves Retained for Compatibility
Algorithms
The following algorithms are available in the OracleUcrypto provider:
Table 4-28 The OracleUcrypto Provider Algorithm Names for Engine Classes
Table 4-28 (Cont.) The OracleUcrypto Provider Algorithm Names for Engine Classes
Keysize Restrictions
The OracleUcrypto provider does not specify any default keysizes or keysize restrictions;
these are specified by the underlying Solaris Ucrypto library.
#
# Configuration file for the OracleUcrypto provider
#
disabledServices = {
[Link]/CFB128/PKCS5Padding
[Link]/CFB128/NoPadding
}
Algorithms
The following algorithms are available in the Apple provider:
Table 4-29 The Apple Provider Algorithm Name for Engine Classes
Algorithms
The following algorithms are available in the JdkLDAP provider:
Table 4-30 The JdkLDAP Provider Algorithm Names for Engine Classes
Table 4-31 The JdkSASL Provider Algorithm Names for Engine Classes
The Java platform defines a set of programming interfaces for performing cryptographic
operations. These interfaces are collectively known as the Java Cryptography Architecture
(JCA) and the Java Cryptography Extension (JCE). See Java Cryptography Architecture (JCA)
Reference Guide.
The cryptographic interfaces are provider-based. Specifically, applications talk to Application
Programming Interfaces (APIs), and the actual cryptographic operations are performed in
configured providers which adhere to a set of Service Provider Interfaces (SPIs). This
architecture supports different provider implementations. Some providers may perform
cryptographic operations in software; others may perform the operations on a hardware token
(for example, on a smartcard device or on a hardware cryptographic accelerator).
The Cryptographic Token Interface Standard, PKCS#11, is produced by RSA Security and
defines native programming interfaces to cryptographic tokens, such as hardware
cryptographic accelerators and smartcards. Existing applications that use the JCA and JCE
APIs can access native PKCS#11 tokens with the PKCS#11 provider. No modifications to the
application are required. The only requirement is to properly configure the provider.
Although an application can make use of most PKCS#11 features using existing APIs, some
applications might need more flexibility and capabilities. For example, an application might
want to deal with smartcards being removed and inserted dynamically more easily. Or, a
PKCS#11 token might require authentication for some non-key-related operations and
therefore, the application must be able to log into the token without using keystore. The JCA
gives applications greater flexibility in dealing with different providers.
This document describes how native PKCS#11 tokens can be configured into the Java platform
for use by Java applications. It also describes how the JCA makes it easier for applications to
deal with different types of providers, including PKCS#11 providers.
SunPKCS11 Provider
The SunPKCS11 provider, in contrast to most other providers, does not implement
cryptographic algorithms itself. Instead, it acts as a bridge between the Java JCA and JCE
APIs and the native PKCS#11 cryptographic API, translating the calls and conventions
between the two.
This means that Java applications calling standard JCA and JCE APIs can, without
modification, take advantage of algorithms offered by the underlying PKCS#11
implementations, such as, for example,
• Cryptographic smartcards,
• Hardware cryptographic accelerators, and
• High performance software implementations.
Note
Java SE only facilitates accessing native PKCS#11 implementations, it does not itself
include a native PKCS#11 implementation. However, cryptographic devices such as
Smartcards and hardware accelerators often come with software that includes a
PKCS#11 implementation, which you need to install and configure according to
manufacturer's instructions.
SunPKCS11 Requirements
The SunPKCS11 provider requires an implementation of PKCS#11 v2.20 or later to be installed
on the system. This implementation must take the form of a shared-object library (.so on
Solaris and Linux) or dynamic-link library (.dll on Windows or .dylib on macOS). Consult
your vendor documentation to find out if your cryptographic device includes such a PKCS#11
implementation, how to configure it, and what the name of the library file is.
The SunPKCS11 provider supports a number of algorithms, provided that the underlying
PKCS#11 implementation offers them. The algorithms and their corresponding PKCS#11
mechanisms are listed in the table in SunPKCS11 Provider Supported Algorithms.
SunPKCS11 Configuration
The SunPKCS11 provider is in the module [Link]. To use the provider, you
must first install it statically or programmatically.
To install the provider statically, add the provider to the Java security properties file (java-
home/conf/security/[Link]).
Note
Properties in the [Link] file are typically parsed only once. If you have
modified any property in this file, restart your applications to ensure that the changes
are properly reflected.
For example, here's a fragment of the [Link] file that installs the SunPKCS11 provider
with the configuration file /opt/bar/cfg/[Link].
To install the provider dynamically, create an instance of the provider with the appropriate
configuration filename and then install it. Here is an example.
Note
Save the returned Provider object from the configure method, then add that
object, as demonstrated in this example:
p = [Link](configName);
[Link](p);
Don't add the provider from which you called the configure method:
[Link](configName);
[Link](p);
If this provider cannot be configured in-place, then a new provider is created and
returned. Therefore, always use the provider returned from the configure method.
To use more than one slot per PKCS#11 implementation, or to use more than one PKCS#11
implementation, simply repeat the installation for each with the appropriate configuration file.
This will result in a SunPKCS11 provider instance for each slot of each PKCS#11
implementation.
The configuration file is a text file that contains entries in the following format:
attribute=value
The valid values for attribute and value are described in the table in this section:
The two mandatory attributes are name and library.
Here is a sample configuration file:
name = FooAccelerator
library = /opt/foo/lib/[Link]
Note
The cleaner thread will switch to
the [Link]
frequency if native PKCS11
references for cleaning are
detected.
Note
The cleaner thread will switch to
the [Link]
frequency after 200 failed tries,
that is, when no references are
found in the queue.
description Description of this provider Specifies the string that the provider instance's
instance [Link]() method returns. If no string is
specified, then a default description is returned.
destroyTokenAfterLogout Boolean value, default: false If true, then when
[Link]() is
called from the SunPKCS11 provider instance, the
underlying token object will be destroyed and resources will
be freed. This essentially renders the SunPKCS11 provider
instance unusable after logout() calls.
Note
You should not add a
SunPKCS11 provider with this
attribute set to true to the
system provider list because the
provider object is not useable
after logout() is called.
enabledMechanisms = {
CKM_RSA_PKCS
CKM_RSA_PKCS_KEY_PAIR_GEN
}
Attributes Configuration
The attributes option allows you to specify additional PKCS#11 attributes that should be set
when creating PKCS#11 key objects. By default, the SunPKCS11 provider only specifies
mandatory PKCS#11 attributes when creating objects. For example, for RSA public keys it
specifies the key type and algorithm (CKA_CLASS and CKA_KEY_TYPE) and the key values
for RSA public keys (CKA_MODULUS and CKA_PUBLIC_EXPONENT). The PKCS#11 library
you are using will assign implementation specific default values to the other attributes of an
RSA public key, for example that the key can be used to encrypt and verify messages
(CKA_ENCRYPT and CKA_VERIFY = true).
The attributes option can be used if you do not like the default values your PKCS#11
implementation assigns or if your PKCS#11 implementation does not support defaults and
requires a value to be specified explicitly. Note that specifying attributes that your PKCS#11
implementation does not support or that are invalid for the type of key in question may cause
the operation to fail at runtime.
The option can be specified zero or more times. The options are processed in the order
specified in the configuration file. The attributes option has the format:
Valid values for keyalgorithm are one of the CKK_xxx constants from the PKCS#11
specification, or * to match keys of any algorithm. See SunPKCS11 Provider Supported
Algorithms.
The attribute names and values are specified as a list of one or more name-value pairs. name
must be a CKA_xxx constant from the PKCS#11 specification, for example CKA_SENSITIVE.
value can be one of the following:
• null, indicating that this attribute should not be specified when creating objects.
If the attributes option is specified multiple times, the entries are processed in the order
specified with the attributes aggregated and later attributes overriding earlier ones. For
example, consider the following configuration file excerpt:
attributes(*,CKO_PRIVATE_KEY,*) = {
CKA_SIGN = true
}
attributes(*,CKO_PRIVATE_KEY,CKK_DH) = {
CKA_SIGN = null
}
attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
CKA_DECRYPT = true
}
The first entry says to specify CKA_SIGN = true for all private keys. The second option
overrides that with null for Diffie-Hellman private keys, so the CKA_SIGN attribute will not
specified for them at all. Finally, the third option says to also specify CKA_DECRYPT = true for
RSA private keys. That means RSA private keys will have both CKA_SIGN = true and
CKA_DECRYPT = true set.
There is also a special form of the attributes option. You can write attributes =
compatibility in the configuration file. That is a shortcut for a whole set of attribute
statements. They are designed to provider maximum compatibility with existing Java
applications, which may expect, for example, all key components to be accessible and secret
keys to be usable for both encryption and decryption. The compatibility attributes line can be
used together with other attributes lines, in which case the same aggregation and overriding
rules apply as described earlier.
name = NSScrypto
nssLibraryDirectory = /opt/tests/nss/lib
nssDbMode = noDb
attributes = compatibility
name = NSSfips
nssLibraryDirectory = /opt/tests/nss/lib
nssSecmodDirectory = /opt/tests/nss/fipsdb
nssModule = fips
Troubleshooting PKCS#11
There could be issues with PKCS#11 which requires debugging. To show debug info about
Library, Slots, Token, and Mechanism, add showInfo=true in the SunPKCS11 provider
configuration file, which is <java-home>/conf/security/[Link] or
the configuration file that you specified statically or dynamically as described in SunPKCS11
Configuration.
For additional debugging info, users can start or restart the Java processes with one of the
following options:
• For general SunPKCS11 provider debugging info:
-[Link]=sunpkcs11
• For PKCS#11 keystore specific debugging info:
-[Link]=pkcs11keystore
have a performance impact. Once the issue has been identified, only that specific mechanism
should remain disabled.
Note
This step is only applicable to the SunPKCS11 provider when backed by the
default Solaris PKCS#11 provider file (<java_home>/conf/security/
[Link]).
2. Disable PKCS#11 for all Java processes run with a particular Java installation: This can be
done dynamically by using the API (not shown in this section) or statically by editing the
<java_home>/conf/security/[Link] file and commenting out the SunPKCS11
security provider (do not forget to re-number the order of providers, if necessary) as
follows:
#
# List of providers and their preference orders:
#
[Link].1=SUN
[Link].2=SunRsaSign
[Link].3=SunEC
[Link].4=SunJSSE
[Link].5=SunJCE
[Link].6=SunJGSS
[Link].7=SunSASL
[Link].8=XMLDSig
[Link].9=SunPCSC
[Link].10=JdkLDAP
[Link].11=JdkSASL
[Link].12=SunMSCAPI
#[Link].13=SunPKCS11
Start or restart the Java processes being run on this installation of Java.
Note
To disable the PKCS#11 SecureRandom implementation only, you can add
SecureRandom to the list of disabled mechanisms in the <java-home>/conf/
security/[Link] file:
name = Solaris
library = /usr/lib/$ISA/[Link]
handleStartupErrors = ignoreAll
# Use the X9.63 encoding for EC points (do not wrap in an ASN.1
OctetString).
useEcX963Encoding = true
attributes = compatibility
disabledMechanisms = {
CKM_DSA_KEY_PAIR_GEN
SecureRandom
}
Application Developers
Java applications can use the existing JCA and JCE APIs to access PKCS#11 tokens through
the SunPKCS11 provider.
Token Login
You can login to the keystore using a Personal Identification Number and perform PKCS#11
operations.
Certain PKCS#11 operations, such as accessing private keys, require a login using a Personal
Identification Number, or PIN, before the operations can proceed. The most common type of
operations that require login are those that deal with keys on the token. In a Java application,
such operations often involve first loading the keystore. When accessing the PKCS#11 token
as a keystore via the [Link] class, you can supply the PIN in the password
input parameter to the load method. The PIN will then be used by the SunPKCS11 provider for
logging into the token. Here is an example.
This is fine for an application that treats PKCS#11 tokens as static keystores. For an
application that wants to accommodate PKCS#11 tokens more dynamically, such as
smartcards being inserted and removed, you can use the new [Link] class. Here
is an example of how to initialize the builder for a PKCS#11 keystore with a callback handler.
[Link] chp =
new [Link](new MyGuiCallbackHandler());
[Link] builder =
[Link]("PKCS11", null, chp);
For the SunPKCS11 provider, the callback handler must be able to satisfy a
PasswordCallback, which is used to prompt the user for the PIN. Whenever the application
needs access to the keystore, it uses the builder as follows.
KeyStore ks = [Link]();
Key key = [Link](alias, null);
The builder will prompt for a password as needed using the previously configured callback
handler. The builder will prompt for a password only for the initial access. If the user of the
application continues using the same Smartcard, the user will not be prompted again. If the
user removes and inserts a different smartcard, the builder will prompt for a password for the
new card.
Depending on the PKCS#11 token, there may be non-key-related operations that also require
token login. Applications that use such operations can use the
[Link] class. The AuthProvider class extends from
[Link] and defines methods to perform login and logout operations on a
provider, as well as to set a callback handler for the provider to use.
For the SunPKCS11 provider, the callback handler must be able to satisfy a
PasswordCallback, which is used to prompt the user for the PIN.
Here is an example of how an application might use an AuthProvider to log into the token.
(Note that you must configure the SunPKCS11 provider before using it.)
Provider p = [Link]("SunPKCS11");
AuthProvider aprov = (AuthProvider)[Link](<provider configuration
file>);
[Link](subject, new MyGuiCallbackHandler());
Token Keys
Java Key objects may or may not contain actual key material.
• A software Key object does contain the actual key material and allows access to that
material.
• An unextractable key on a secure token (such as a smartcard) is represented by a Java
Key object that does not contain the actual key material. The Key object only contains a
reference to the actual key.
Applications and providers must use the correct interfaces to represent these different types of
Key objects. Software Key objects (or any Key object that has access to the actual key
material) should implement the interfaces in the [Link] and
[Link] packages (such as DSAPrivateKey). Key objects representing
unextractable token keys should only implement the relevant generic interfaces in the
[Link] and [Link] packages (PrivateKey, PublicKey, or SecretKey).
Note
Once the provider is selected, for example, after the first initialization call, the JDK
won't switch to a different provider for subsequent initialization calls. To reselect a
provider based on a specific Key object, call getInstance() to get a new instance,
and then call this instance's initialization method with the Key object instead of reusing
the older, already-initialized instance.
Although this delayed provider selection is hidden from the application, it does affect the
behavior of the getProvider() method for Cipher, KeyAgreement, Mac, and Signature. If
getProvider() is called before the initialization operation has occurred (and therefore before
provider selection has occurred), then the first provider that supports the requested algorithm is
returned. This may not be the same provider as the one selected after the initialization method
is called. If getProvider() is called after the initialization operation has occurred, then the
actual selected provider is returned. It is recommended that applications only call
getProvider() after they have called the relevant initialization method.
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
JAAS KeyStoreLoginModule
The JDK comes with a JAAS keystore login module, KeyStoreLoginModule, that allows an
application to authenticate using its identity in a specified keystore. After authentication, the
application would acquire its principal and credentials information (certificate and private key)
from the keystore. By using this login module and configuring it to use a PKCS#11 token as a
keystore, the application can acquire this information from a PKCS#11 token.
Use the following options to configure the KeyStoreLoginModule to use a PKCS#11 token as
the keystore.
• keyStoreURL="NONE"
• keyStoreType="PKCS11"
• keyStorePasswordURL=some_pin_url
where
some_pin_url
The location of the PIN. If the keyStorePasswordURL option is omitted, then the login module
will get the PIN via the application's callback handler, supplying it with a PasswordCallback .
Here is an example of a configuration file that uses a PKCS#11 token as a keystore.
other {
[Link] required
keyStoreURL="NONE"
keyStoreType="PKCS11"
keyStorePasswordURL="file:/home/joe/scpin";
};
If more than one SunPKCS11 provider has been configured dynamically or in the
[Link] security properties file, you can use the keyStoreProvider option to target a
specific provider instance. The argument to this option is the name of the provider. For the
SunPKCS11 provider, the provider name is of the form SunPKCS11-TokenName, where
TokenName is the name suffix that the provider instance has been configured with, as detailed in
Table 5-1. For example, the following configuration file names the PKCS#11 provider instance
with name suffix SmartCard.
other {
[Link] required
keyStoreURL="NONE"
keyStoreType="PKCS11"
keyStorePasswordURL="file:/home/joe/scpin"
keyStoreProvider="SunPKCS11-SmartCard";
};
Some PKCS#11 tokens support login via a protected authentication path. For example, a
smartcard may have a dedicated PIN-pad to enter the pin. Biometric devices will also have
their own means to obtain authentication information. If the PKCS#11 token has a protected
authentication path, then use the protected=true option and omit the keyStorePasswordURL
option. Here is an example of a configuration file for such a token.
other {
[Link] required
keyStoreURL="NONE"
keyStoreType="PKCS11"
protected=true;
};
The PIN can be specified using the -storepass option. If none has been specified, then
keytool and jarsigner will prompt for the token PIN. If the token has a protected
authentication path (such as a dedicated PIN-pad or a biometric reader), then the -protected
option must be specified, and no password options can be specified.
If more than one SunPKCS11 provider has been configured in the [Link] security
properties file, you can use the -providerName option to target a specific provider instance.
The argument to this option is the name of the provider.
• -providerName providerName
For the SunPKCS11 provider, providerName is of the form SunPKCS11-TokenName where:
TokenName
The name suffix that the provider instance has been configured with, as detailed in Table 5-1.
For example, the following command lists the contents of the PKCS#11 keystore provider
instance with name suffix SmartCard.
If the SunPKCS11 provider has not been configured in the [Link] security properties
file, you can use the following options to instruct keytool and jarsigner to install the provider
dynamically.
• -providerClass [Link].pkcs11.SunPKCS11
• -providerArg ConfigFilePath
ConfigFilePath
The path to the token configuration file. Here is an example of a command to list a PKCS#11
keystore when the SunPKCS11 provider has not been configured in the [Link] file.
Note
Sometimes the hardware token is too small to store the certificates. You can use the
jarsigner tool's -certchain option to load them from an external file.
[Link](in, out);
}
Where
keystore_provider
The keystore provider name (for example, "SunPKCS11-SmartCard").
some_password_url
A URL pointing to the location of the token PIN. Both keystore_provider and the
keystorePasswordURL line are optional. If keystore_provider has not been specified, then the
first configured provider that supports the specified keystore type is used. If the
keystorePasswordURL line has not been specified, then no password is used.
Provider Developers
The [Link] class enables provider developers to more easily support
PKCS#11 tokens and cryptographic services through provider services and parameter support.
See Example Provider for an example of a simple provider designed to demonstrate provider
services and parameter support.
Provider Services
For each service implemented by the provider, there must be a property whose name is the
type of service (Cipher, Signature, etc), followed by a period and the name of the algorithm to
which the service applies. The property value must specify the fully qualified name of the class
implementing the service. Here is an example of a provider setting
[Link] property to have the value
[Link].
put("[Link]", "[Link]")
The public static nested class [Link] encapsulates the properties of a provider
service (including its type, attributes, algorithm name, and algorithm aliases). Providers can
instantiate [Link] objects and register them by calling the [Link]()
method. This is equivalent to creating a Property entry and calling the [Link]()
method. Note that legacy Property entries registered via [Link] are still supported.
Here is an example of a provider creating a Service object with the KeyAgreement type, for the
DiffieHellman algorithm, implemented by the class
[Link].
Using [Link] objects instead of legacy Property entries has a couple of major
benefits. One benefit is that it allows the provider to have greater flexibility when Instantiating
Engine Classes. Another benefit is that it allows the provider to test Parameter Support. These
features are discussed in detail next.
Parameter Support
The Java Cryptography framework may attempt a fast check to determine whether a provider's
service implementation can use an application-specified parameter. To perform this fast check,
the framework calls [Link]().
The framework relies on this fast test during delayed provider selection (see Delayed Provider
Selection). When an application invokes an initialization method and passes it a Key object, the
framework asks an underlying provider whether it supports the object by calling its
[Link]() method. If supportsParameter() returns false, the framework
can immediately remove that provider from consideration. If supportsParameter() returns
true, the framework passes the Key object to that provider's initialization engine class
implementation. A provider that requires software Key objects should override this method to
return false when it is passed non-software keys. Likewise, a provider for a PKCS#11 token
that contains unextractable keys should only return true for Key objects that it created, and
which therefore correspond to the keys on its respective token.
Note
The default implementation of supportsParameter() returns true. This allows existing
providers to work without modification. However, because of this lenient default
implementation, the framework must be prepared to catch exceptions thrown by
providers that reject the Key object inside their initialization engine class
implementations. The framework treats these cases the same as when
supportsParameter() returns false.
Parameter Support
The Java Cryptography framework may attempt a fast check to determine whether a provider's
service implementation can use an application-specified parameter. To perform this fast check,
the framework calls [Link]().
The framework relies on this fast test during delayed provider selection (see Delayed Provider
Selection). When an application invokes an initialization method and passes it a Key object, the
framework asks an underlying provider whether it supports the object by calling its
[Link]() method. If supportsParameter() returns false, the framework
can immediately remove that provider from consideration. If supportsParameter() returns
true, the framework passes the Key object to that provider's initialization engine class
implementation. A provider that requires software Key objects should override this method to
return false when it is passed non-software keys. Likewise, a provider for a PKCS#11 token
that contains unextractable keys should only return true for Key objects that it created, and
which therefore correspond to the keys on its respective token.
Note
The default implementation of supportsParameter() returns true. This allows existing
providers to work without modification. However, because of this lenient default
implementation, the framework must be prepared to catch exceptions thrown by
providers that reject the Key object inside their initialization engine class
implementations. The framework treats these cases the same as when
supportsParameter() returns false.
Note
SunPKCS11 can be instructed to ignore mechanisms by using the
disabledMechanisms and enabledMechanisms configuration directives (see
SunPKCS11 Configuration).
For Elliptic Curve mechanisms, the SunPKCS11 provider will only use keys that use the
namedCurve choice as encoding for the parameters and only allow the uncompressed point
format. The SunPKCS11 provider assumes that a token supports all standard named domain
parameters.
Note
For Elliptic Curve (EC) names, the SunPKCS11 provider supports any EC name that
the SunEC provider supports as long as the token supports it; see Supported Elliptic
Curve Names in The SunEC Provider.
Note
Changes may be made in future releases to maximize interoperability with as many
existing PKCS#11 libraries as possible.
Read-Only Access
To map existing objects stored on a PKCS#11 token to KeyStore entries, the SunPKCS11
provider's KeyStore implementation performs the following operations.
1. A search for all private key objects on the token is performed by calling
C_FindObjects[Init|Final]. The search template includes the following attributes:
• CKA_TOKEN = true
• CKA_CLASS = CKO_PRIVATE_KEY
2. A search for all certificate objects on the token is performed by calling
C_FindObjects[Init|Final]. The search template includes the following attributes:
• CKA_TOKEN = true
• CKA_CLASS = CKO_CERTIFICATE
3. Each private key object is matched with its corresponding certificate by retrieving their
respective CKA_ID attributes. A matching pair must share the same unique CKA_ID.
For each matching pair, the certificate chain is built by following the issuer->subject path.
From the end entity certificate, a call for C_FindObjects[Init|Final] is made with a
search template that includes the following attributes:
• CKA_TOKEN = true
• CKA_CLASS = CKO_CERTIFICATE
Write Access
To create new KeyStore entries on a PKCS#11 token to KeyStore entries, the SunPKCS11
provider's KeyStore implementation performs the following operations.
1. When creating a KeyStore entry (during [Link], for example), C_CreateObject
is called with CKA_TOKEN=true to create token objects for the respective entry contents.
Private key objects are stored with CKA_PRIVATE=true. The KeyStore alias (UTF8-
encoded) is set as the CKA_ID for both the private key and the corresponding end entity
certificate. The KeyStore alias is also set as the CKA_LABEL for the end entity certificate
object.
Each certificate in a private key entry's chain is also stored. The CKA_LABEL is not set for
CA certificates. If a CA certificate is already in the token, a duplicate is not stored.
Secret key objects are stored with CKA_PRIVATE=true. The KeyStore alias is set as the
CKA_LABEL.
2. If an attempt is made to convert a session object to a token object (for example, if
[Link] is called and the private key object in the specified entry is a session
object), then C_CopyObject is called with CKA_TOKEN=true.
3. If multiple certificates in the token are found to share the same CKA_LABEL, then the write
capabilities to the token are disabled.
4. Since the PKCS#11 specification does not allow regular applications to set
CKA_TRUSTED=true (only token initialization applications may do so), trusted certificate
entries can not be created.
Miscellaneous
In addition to the searches listed previously, the following searches may be used by the
SunPKCS11 provider's KeyStore implementation to perform internal functions. Specifically,
C_FindObjects[Init|Final] may be called with any of the following attribute templates:
• CKA_TOKEN true
CKA_CLASS CKO_CERTIFICATE
CKA_SUBJECT [subject DN]
• CKA_TOKEN true
CKA_CLASS CKO_SECRET_KEY
CKA_LABEL [label]
• CKA_TOKEN true
CKA_CLASS CKO_CERTIFICATE or CKO_PRIVATE_KEY
CKA_ID [cka_id]
Example Provider
The following is an example of a simple provider that demonstrates features of the Provider
class.
package [Link];
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
/**
* Example provider that demonstrates some Provider class features.
*
* . Implement multiple different algorithms in a single class.
* Previously each algorithm needed to be implemented in a separate class
* (e.g. one for SHA-256, one for SHA-384, etc.)
*
* . Multiple concurrent instances of the provider frontend class each
* associated with a different backend.
*
* . It uses "unextractable" keys and lets the framework know which key
* objects it can and cannot support
*
* Note that this is only a simple example provider designed to demonstrate
* several of the new features. It is not explicitly designed for efficiency.
*/
public final class ExampleProvider extends Provider {
// The shell of the representation the crypto backend uses for keys.
private static final class KeyHandle {
// fill in code
}
}
// Fetch the (Provider, String) constructor.
Constructor cons = [Link](paramTypes);
// Invoke constructor and return the SPI object.
Object obj = [Link](new Object[] {provider,
getAlgorithm()});
return obj;
} catch (Exception e) {
throw new NoSuchAlgorithmException("Could not instantiate
service", e);
}
}
}
in);
} else {
out = [Link](algorithm, [Link],
in);
}
buffer = new ByteArrayOutputStream();
return out;
}
// code for remaining CipherSpi methods goes here
}
// our SecretKey implementation. All our keys are stored in our crypto
// backend, we only have an opaque handle available. There is no
// encoded form of these keys.
private static final class MySecretKey implements SecretKey {
return null;
}
byte[] encoded = [Link]();
KeyHandle handle = [Link](algorithm,
encoded);
return new MySecretKey(provider, algorithm, handle);
}
}
}
Related Documentation
This document assumes you have already read the following:
• Java SE Platform Security Architecture
• Java SE Security Tutorial
A supplement to this guide is the JAAS LoginModule Developer's Guide, intended for
experienced programmers who require the ability to write a LoginModule implementing an
authentication technology.
The following tutorials for JAAS authentication and authorization can be run by everyone:
• JAAS Authentication Tutorial
• JAAS Authorization Tutorial
Similar tutorials for JAAS authentication and authorization, but which demonstrate the use of a
Kerberos LoginModule and thus which require a Kerberos installation, can be found at
• JAAS Authentication
• JAAS Authorization
These two tutorials are a part of Introduction to JAAS and Java GSS-API Tutorials that utilize
Kerberos as the underlying technology for authentication and secure communication.
Common Classes
Common classes are those shared by both the JAAS authentication and authorization
components.
The key JAAS class is [Link], which represents a grouping of related
information for a single entity such as a person. It encompasses the entity's Principals, public
credentials, and private credentials.
Note that the [Link] interface is used to represent a Principal. Also note
that a credential, as defined by JAAS, may be any Object.
Subject
To authorize access to resources, applications first need to authenticate the source of the
request. The JAAS framework defines the term subject to represent the source of a request. A
subject may be any entity, such as a person or a service. Once the subject is authenticated, a
[Link] is populated with associated identities, or Principals. A
Subject may have many Principals. For example, a person may have a name Principal
("John Doe") and a SSN Principal ("123-45-6789"), which distinguish it from other subjects.
A Subject may also own security-related attributes, which are referred to as credentials; see
the section Credentials. Sensitive credentials that require special protection, such as private
cryptographic keys, are stored within a private credential Set. Credentials intended to be
shared, such as public key certificates, are stored within a public credential Set. Different
permissions are required to access and modify the different credential Sets.
public Subject();
The first constructor creates a Subject with empty (non-null) Sets of Principals and
credentials. The second constructor creates a Subject with the specified Sets of Principals
and credentials. It also has a boolean argument which can be used to make the Subject read-
only. In a read-only Subject, the Principal and credential Sets are immutable.
An application writer does not have to instantiate a Subject. If the application instantiates a
LoginContext and does not pass a Subject to the LoginContext constructor, the
LoginContext instantiates a new empty Subject. See the LoginContext section.
If a Subject was not instantiated to be in a read-only state, it can be set read-only by calling
the following method:
To retrieve the Principals associated with a Subject, two methods are available:
The first method returns all Principals contained in the Subject, while the second method
only returns those Principals that are an instance of the specified Class c, or an instance of a
subclass of Class c. An empty set will be returned if the Subject does not have any associated
Principals.
To retrieve the public credentials associated with a Subject, these methods are available:
The behavior of these methods is similar to that for the getPrincipals methods, except in this
case the public credentials are being obtained.
To access private credentials associated with a Subject, the following methods are available:
The behavior of these methods is similar to that for the getPrincipals and
getPublicCredentials methods.
Subject subject;
Principal principal;
Object credential;
. . .
The Subject class also includes the following methods inherited from [Link].
Both methods first associate the specified subject with the current Thread's
AccessControlContext, and then execute the action. This achieves the effect of having the
action run as the subject. The first method can throw runtime exceptions but normal
execution has it returning an Object from the run method of its action argument. The second
method behaves similarly except that it can throw a checked exception from its
PrivilegedExceptionAction run method. An AuthPermission with target "doAs" is required
to call the doAs methods.
[Link] Example
Here is an example utilizing the first doAs method. Assume that someone named "Bob" has
been authenticated by a LoginContext (see the LoginContext) and as a result a Subject was
populated with a Principal of class [Link], and that Principal has
the name "BOB". Also assume that a SecurityManager has been installed, and that the
following exists in the access control policy (see Policy for more details on the policy file).
Subject bob;
// Set bob to the Subject created during the
// authentication process
During execution, ExampleAction will encounter a security check when it makes a call to
[Link](). However, since ExampleAction is running as "BOB", and the policy in this
example grants the necessary FilePermission to "BOB", the ExampleAction will pass the
security check. If the grant statement in the policy is altered (adding an incorrect CodeBase or
changing the Principal to "MOE", for example), then a SecurityException will be thrown.
An AccessControlContext contains information about all the code executed since the
AccessControlContext was instantiated, including the code location and the permissions the
code is granted by the policy. In order for an access control check to succeed, the policy must
grant each code item referenced by the AccessControlContext the required permissions.
separate doAs operation for each request. To start each doAs action "fresh," and without the
restrictions of the current server AccessControlContext, the server can call doAsPrivileged
and pass in a nullAccessControlContext.
Principals
As mentioned previously, once a Subject is authenticated, it is populated with associated
identities, or Principals. A Subject may have many Principals. For example, a person
may have a name Principal ("John Doe") and an SSN Principal ("123-45-6789"), which
distinguish it from other Subjects. A Principal must implement the
[Link] and [Link] interfaces. See Subject for
information about ways to update the Principals associated with a Subject.
Credentials
In addition to associated Principals, a Subject may own security-related attributes, which are
referred to as credentials. A credential may contain information used to authenticate the
subject to new services. Such credentials include passwords, Kerberos tickets, and public key
certificates. Credentials might also contain data that simply enables the subject to perform
certain activities. Cryptographic keys, for example, represent credentials that enable the
subject to sign or encrypt data. Public and private credential classes are not part of the core
JAAS class library. Any class, therefore, can represent a credential.
Public and private credential classes are not part of the core JAAS class library. Developers,
however, may elect to have their credential classes implement two interfaces related to
credentials: Refreshable and Destroyable.
Refreshable
The [Link] interface provides the capability for a credential to
refresh itself. For example, a credential with a particular time-restricted lifespan may implement
this interface to allow callers to refresh the time period for which it is valid. The interface has
two abstract methods:
boolean isCurrent();
This method updates or extends the validity of the credential. The method implementation
should perform an
AuthPermission("refreshCredential")
security check to ensure the caller has permission to refresh the credential.
Destroyable
The [Link] interface provides the capability of destroying the
contents within a credential. The interface has two abstract methods:
boolean isDestroyed();
Destroys and clears the information associated with this credential. Subsequent calls to certain
methods on this credential will result in an IllegalStateException being thrown. The method
implementation should perform an AuthPermission("destroyCredential") security check to
ensure the caller has permission to destroy the credential.
LoginContext
The [Link] class provides the basic methods used to
authenticate subjects, and provides a way to develop an application independent of the
underlying authentication technology. The LoginContext consults a Configuration to
determine the authentication services, or LoginModule(s), configured for a particular
application. Therefore, different LoginModules can be plugged in under an application without
requiring any modifications to the application itself.
LoginContext offers four constructors from which to choose:
All of the constructors share a common parameter: name. This argument is used by the
LoginContext as an index into the login Configuration to determine which LoginModules are
configured for the application instantiating the LoginContext. Constructors that do not take a
Subject as an input parameter instantiate a new Subject. Null inputs are disallowed for all
constructors. Callers require an AuthPermission with target "createLoginContext.<name>" to
instantiate a LoginContext. Here, <name> refers to the name of the login configuration entry
that the application references in the name parameter for the LoginContext instantiation.
See CallbackHandler for information on what a CallbackHandler is and when you may need
one.
Actual authentication occurs with a call to the following method:
When login is invoked, all of the configured LoginModules are invoked to perform the
authentication. If the authentication succeeded, the Subject (which may now hold Principals,
public credentials, and private credentials) can be retrieved by using the following method:
To logout a Subject and remove its authenticated Principals and credentials, the following
method is provided:
The following code sample demonstrates the calls necessary to authenticate and logout a
Subject:
...
LoginModule
The LoginModule interface gives developers the ability to implement different kinds of
authentication technologies that can be plugged in under an application. For example, one type
Note: If you are an application writer, you do not need to understand the workings of
LoginModules. All you have to know is how to write your application and specify configuration
information (such as in a login configuration file) such that the application will be able to utilize
the LoginModule specified by the configuration to authenticate the user.
If, on the other hand, you are a programmer who wishes to write a LoginModule implementing
an authentication technology, see the Java Authentication and Authorization Service (JAAS):
LoginModule Developer's Guide for detailed step-by-step instructions.
CallbackHandler
In some cases a LoginModule must communicate with the user to obtain authentication
information. LoginModules use a [Link]
for this purpose. Applications implement the CallbackHandler interface and pass it to the
LoginContext, which forwards it directly to the underlying LoginModules. A LoginModule uses
the CallbackHandler both to gather input from users (such as a password or smart card pin
number) or to supply information to users (such as status information). By allowing the
application to specify the CallbackHandler, underlying LoginModules can remain independent
of the different ways applications interact with users. For example, the implementation of a
CallbackHandler for a GUI application might display a window to solicit input from a user. On
the other hand, the implementation of a CallbackHandler for a non-GUI tool might simply
prompt the user for input directly from the command line.
CallbackHandler
The CallbackHandler documentation has a lengthy example not included in this document that
readers may want to examine.
Callback
The [Link] package contains the Callback interface as well as
several implementations. LoginModules may pass an array of Callbacks directly to the handle
method of a CallbackHandler.
Please consult the various Callback APIs for more information on their use.
Authorization Classes
To make JAAS authorization take place, granting access control permissions based not just on
what code is running but also on who is running it, the following is required:
• The user must be authenticated, as described in the LoginContext section.
• The Subject that is the result of authentication must be associated with an access control
context, as described in the Subject section.
• Principal-based entries must be configured in the security policy.
The following sections describe the Policy abstract class and the authorization-specific
classes AuthPermission and PrivateCredentialPermission.
Policy
The [Link] class is an abstract class for representing the system-wide
access control policy. The Policy API supports Principal-based queries.
As a default, the JDK provides a file-based subclass implementation, which was upgraded to
support Principal-based grant entries in policy files.
Policy files and the structure of entries within them are described in Default Policy
Implementation and Policy File Syntax.
AuthPermission
The [Link] class encapsulates the basic permissions
required for JAAS. An AuthPermission contains a name (also referred to as a "target name")
but no actions list; you either have the named permission or you don't.
In addition to its inherited methods (from the [Link] class), an
AuthPermission has two public constructors:
The first constructor creates a new AuthPermission with the specified name. The second
constructor also creates a new AuthPermission object with the specified name, but has an
additional actions argument which is currently unused and should be null. This constructor
exists solely for the Policy object to instantiate new Permission objects. For most other code,
the first constructor is appropriate.
Currently the AuthPermission object is used to guard access to the Policy, Subject,
LoginContext, and Configuration objects. Refer to the AuthPermission JavaDoc API
documentation for the list of valid names that are supported.
PrivateCredentialPermission
The [Link] class protects access to a
Subject's private credentials and provides one public constructor:
• The Login Configuration File for the JAAS Authentication Tutorial describes
sample_jaas.config, which is a sample login configuration file used by both tutorials.
• [Link] is a sample policy file granting permissions required by the code for
the authentication tutorial.
• [Link] is a sample policy file granting permissions required by the code for
the authorization tutorial.
• [Link] is the class specified by the tutorials' login configuration file
(sample_jaas.config) as the class implementing the desired underlying authentication.
SampleLoginModule's user authentication consists of simply verifying that the name and
password specified by the user have specific values.
• [Link] is a sample class implementing the Principal interface. It is
used by SampleLoginModule.
See the tutorials for detailed information about the applications, the policy files, and the login
configuration file.
Application writers do not need to understand the code for [Link] or
[Link], as explained in the tutorials. Programmers who wish to write
LoginModules can learn how to do so by reading the Java Authentication and Authorization
Service (JAAS): LoginModule Developer's Guide.
• [Link]
• [Link].n
The following pre-existing properties are also relevant for JAAS users:
• [Link]
• [Link].n
The following example demonstrates how to configure these properties. In this example, we
leave the values provided in the default [Link] file for the [Link],
[Link].n, and [Link] Security Properties. The default
[Link] file also lists a value for the [Link].n Security Property, but it is
commented out. In the following example, it is not commented.
...
#
# Class to instantiate as the [Link]
# provider.
#
[Link]=[Link]
#
# Default login configuration file
#
#[Link].1=file:${[Link]}/.[Link]
#
# Class to instantiate as the system Policy. This is the name of the class
# that will be used as the Policy object. The system class loader is used to
# locate this class.
#
[Link]=[Link]
...
Note
Modifications made to this file may be overwritten by subsequent JDK updates.
However, an alternate [Link] properties file may be specified from the
command line via the system property [Link]=<URL>. This
properties file appends to the system properties file. If both properties files specify
values for the same key, the value from command-line properties file is selected, as it
is the last one loaded.
Also, specifying [Link]==<URL> (using two equals signs), then
that properties file will completely override the system properties file.
To disable the ability to specify an additional properties file from the command line, set
the key [Link] to false in the system properties file. It is
set to true by default.
For example:
[Link]=[Link]
[Link]=[Link]
Note that there is no means to dynamically set the login configuration provider from the
command line.
[Link].1=file:C:/config/.[Link]
[Link].2=file:C:/users/foo/.[Link]
If the location of the configuration files is not set in the [Link] properties file, and also
is not specified dynamically from the command line (via the -
[Link] option), JAAS attempts to load a default configuration
from
file:${[Link]}/.[Link]
Policy Provider
The default policy implementation can be replaced by specifying the alternative provider class
implementation in the [Link] property.
For example:
[Link]=[Link]
If the Security property [Link] is not found, or is left unspecified, then the Policy is
set to the default value:
[Link]=[Link]
Note that there is no means to dynamically set the policy provider from the command line.
[Link].1=file:C:/policy/.[Link]
[Link].2=file:C:/users/foo/.[Link]
If the location of the policy file(s) is not set in the [Link] properties file, and is not
specified dynamically from the command line (via the -[Link] option), the
access control policy defaults to the same policy as that of the system policy file installed with
the JDK. That policy file
• grants all permissions to standard extensions
• allows anyone to listen on un-privileged ports
• allows any code to read certain "standard" properties that are not security-sensitive, such
as the [Link] and [Link] properties.
Thus, each login configuration file entry consists of a name followed by one or more
LoginModule-specific entries, where each LoginModule-specific entry is terminated by a
semicolon and the entire group of LoginModule-specific entries is enclosed in braces. Each
configuration file entry is terminated by a semicolon.
Example 6-1 Login Configuration File for JAAS Authentication Tutorial
As an example, the login configuration file used for the JAAS Authentication Tutorial tutorial
contains just one entry, which is
Sample {
[Link] required debug=true;
};
Here, the entry is named Sample and that is the name that the JAAS Authentication tutorial
application ([Link]) uses to refer to this entry. The entry specifies that the
LoginModule to be used to do the user authentication is the SampleLoginModule in the
[Link] package and that this SampleLoginModule is required to "succeed" in order for
authentication to be considered successful. The SampleLoginModule succeeds only if the name
and password supplied by the user are the ones it expects (testUser and testPassword,
respectively).
The name for an entry in a login configuration file is the name that applications use to refer to
the entry when they instantiate a LoginContext, as described in JAAS Authentication
Tutorial in the JAAS authentication tutorial. The name can be whatever name the application
developer wishes to use. Here, the term "application" refers to whatever code does the JAAS
login.
The specified LoginModules are used to control the authentication process. Authentication
proceeds down the list in the exact order specified, as described in the Configuration class.
Login1 {
[Link] required debug=true;
};
Login2 {
[Link] required;
[Link] sufficient;
[Link] requisite debug=true;
The application Login1 only has one configured LoginModule, SampleLoginModule. Therefore,
an attempt by Login1 to authenticate a subject (user or service) will be successful if and only if
the SampleLoginModule succeeds.
The authentication logic for the application Login2 is easier to explain with the following table:
Module Flag Authentic Authentic Authentic Authentic Authentic Authentic Authentic Authentic
Class ation ation ation ation ation ation ation ation
Attempt 1 Attempt 2 Attempt 3 Attempt 4 Attempt 5 Attempt 6 Attempt 7 Attempt 8
SampleLo required pass pass pass pass fail fail fail fail
ginModul
e
NTLoginM sufficient pass fail fail fail pass fail fail fail
odule
SmartCard requisite * pass pass fail * pass pass fail
Kerberos optional * pass fail * * pass fail *
Overall not pass pass pass fail fail fail fail fail
Authenticat applicable
ion
* = trivial value due to control returning to the application because a previous requisite module
failed or a previous sufficient module succeeded.
Note
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
An alternate approach to specifying the location of the login configuration file is to indicate
its URL as the value of a [Link].n property in the security properties file. The
Security Properties file is the [Link] file located in the conf/security directory of
the JDK.
Here, n indicates a consecutively-numbered integer starting with 1. Thus, if desired, you
can specify more than one login configuration file by indicating one file's URL for the
[Link].1 property, a second file's URL for the [Link].2 property,
and so on. If more than one login configuration file is specified (that is, if n > 1), then the
files are read and concatenated into a single configuration.
Here is an example of what would need to be added to the security properties file in order
to indicate the sample_jaas.config login configuration file used by this tutorial. This
example assumes the file is in the C:\AcnTest directory on Windows:
[Link].1=file:C:/AcnTest/sample_jaas.config
(Note that URLs always use forward slashes, regardless of what operating system the user
is running.)
JAAS Tutorials
This page links to two tutorials demonstrating various aspects of the use of JAAS (Java
Authentication and Authorization Service):
• JAAS Authentication Tutorial: Explains how an application can authenticate users using
JAAS.
• JAAS Authorization Tutorial: Explains how to enforce user-based access controls using
JAAS.
The authentication technology used for these tutorials is very basic, just ensuring that the user
specifies a particular name and password. Thus, these tutorials can be run by everyone.
[Link]
Our authentication tutorial application code is contained in a single source file,
[Link]. That file contains two classes:
import [Link].*;
. . .
LoginContext lc =
new LoginContext(<config file entry name>,
<CallbackHandler to be used for user interaction>);
and here is the specific way our tutorial code does the instantiation:
import [Link].*;
. . .
LoginContext lc =
new LoginContext("Sample",
new MyCallbackHandler());
[Link]();
The LoginContext's login method then calls methods in the SampleLoginModule to perform
the login and authentication. The SampleLoginModule will utilize the MyCallbackHandler to
obtain the user name and password. Then the SampleLoginModule will check that the name
and password are the ones it expects.
If authentication is successful, the SampleLoginModule populates the Subject with a
Principal representing the user. The Principal the SampleLoginModule places in the
Subject is an instance of SamplePrincipal, which is a sample class implementing the
[Link] interface.
The calling application can subsequently retrieve the authenticated Subject by calling the
LoginContext's getSubject method, although doing so is not necessary for this tutorial.
[Link]
package sample;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
/**
* This Sample application attempts to authenticate a user
* and reports whether or not the authentication was successful.
*/
public class SampleAcn {
/**
* Attempt to authenticate the user.
*
* @param args input arguments for this application. These are ignored.
*/
public static void main(String[] args) {
int i;
for (i = 0; i < 3; i++) {
try {
// attempt authentication
[Link]();
[Link]("Authentication failed:");
[Link](" " + [Link]());
try {
[Link]().sleep(3000);
} catch (Exception e) {
// ignore
}
}
}
[Link]("Authentication succeeded!");
}
}
/**
* The application implements the CallbackHandler.
*
* <p> This application is text-based. Therefore it displays information
* to the user using the OutputStreams [Link] and [Link],
* and gathers input from the user using the InputStream [Link].
*/
class MyCallbackHandler implements CallbackHandler {
/**
* Invoke an array of Callbacks.
*
* <p>
*
* @param callbacks an array of <code>Callback</code> objects which
contain
* the information requested by an underlying security
* service to be retrieved or displayed.
*
* @exception [Link] if an input or output error occurs. <p>
*
[Link]([Link]());
[Link]();
[Link]((new BufferedReader
(new InputStreamReader([Link]))).readLine());
} else {
throw new UnsupportedCallbackException
(callbacks[i], "Unrecognized Callback");
}
}
}
}
The tutorial sample code supplies its own CallbackHandler implementation, the
MyCallbackHandler class in page 19.
} else {
throw new UnsupportedCallbackException
(callbacks[i], "Unrecognized Callback");
}
}
}
MyCallbackHandler handles three types of Callbacks: NameCallback to prompt the user for a
user name, PasswordCallback to prompt for a password, and TextOutputCallback to
report any error, warning, or other messages the SampleLoginModule wishes to send to the
user.
The handle method handles a TextOutputCallback by extracting the message to be
reported and then printing it to [Link], optionally preceded by additional wording that
depends on the message type. The message to be reported is determined by calling the
TextOutputCallback's getMessage method and the type by calling its getMessageType
method. Here is the code for handling a TextOutputCallback:
The handle method handles a NameCallback by prompting the user for a user name. It does
this by printing the prompt to [Link]. It then sets the name for use by the
SampleLoginModule by calling the NameCallback's setName method, passing it the name
typed by the user:
[Link]([Link]());
[Link]();
[Link]((new BufferedReader
(new InputStreamReader([Link]))).readLine());
[Link]([Link]());
[Link]();
[Link]([Link]().readPassword());
Important: If you are an application writer, you do not need to know how to write a
LoginModule or a Principal implementation. You do not need to examine the
SampleLoginModule or SamplePrincipal code. All you have to know is how to write your
application and specify configuration information (such as in a login configuration file) such that
the application will be able to utilize the LoginModule specified by the configuration to
authenticate the user. You need to determine which LoginModule(s) you want to use and
read the LoginModule's documentation to learn about what options you can specify values
for (in the configuration) to control the LoginModule's behavior.
Any vendor can provide a LoginModule implementation that you can use. Some
implementations are supplied with the JDK from Oracle, as listed in Appendix B: JAAS Login
Configuration File.
Information for programmers who want to write a LoginModule can be found in Java
Authentication and Authorization Service (JAAS): LoginModule Developer's Guide.
[Link]
package [Link];
import [Link].*;
import [Link];
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
/**
* <p> This sample LoginModule authenticates users with a password.
*
* <p> This LoginModule only recognizes one user: testUser
* <p> testUser's password is: testPassword
*
// initial state
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
// configurable option
private boolean debug = false;
// testUser's SamplePrincipal
private SamplePrincipal userPrincipal;
/**
* Initialize this <code>LoginModule</code>.
*
* @param subject the <code>Subject</code> to be authenticated. <p>
*
* @param callbackHandler a <code>CallbackHandler</code> for communicating
* with the end user (prompting for user names and
* passwords, for example). <p>
*
* @param sharedState shared <code>LoginModule</code> state. <p>
*
* @param options options specified in the login
* <code>Configuration</code> for this particular
* <code>LoginModule</code>.
*/
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map<[Link], ?> sharedState,
Map<[Link], ?> options) {
[Link] = subject;
[Link] = callbackHandler;
[Link] = sharedState;
[Link] = options;
/**
* Authenticate the user by prompting for a user name and password.
*
* @return true in all cases since this <code>LoginModule</code>
* should not be ignored.
*
* @exception FailedLoginException if the authentication fails. <p>
*
* @exception LoginException if this <code>LoginModule</code>
* is unable to perform the authentication.
*/
public boolean login() throws LoginException {
try {
[Link](callbacks);
username = ((NameCallback)callbacks[0]).getName();
char[] tmpPassword =
((PasswordCallback)callbacks[1]).getPassword();
if (tmpPassword == null) {
// treat a NULL password as an empty password
tmpPassword = new char[0];
}
password = new char[[Link]];
[Link](tmpPassword, 0,
password, 0, [Link]);
((PasswordCallback)callbacks[1]).clearPassword();
// authentication succeeded!!!
passwordCorrect = true;
if (debug)
[Link]("\t\t[SampleLoginModule] " +
"authentication succeeded");
succeeded = true;
return true;
} else {
/**
* This method is called if the LoginContext's
* overall authentication succeeded
* (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* succeeded).
*
* If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* <code>login</code> method), then this method associates a
* <code>SamplePrincipal</code>
* with the <code>Subject</code> located in the
* <code>LoginModule</code>. If this LoginModule's own
* authentication attempted failed, then this method removes
* any state that was originally saved.
*
* @exception LoginException if the commit fails.
*
* @return true if this LoginModule's own login and commit
* attempts succeeded, or false otherwise.
*/
public boolean commit() throws LoginException {
if (succeeded == false) {
return false;
} else {
// add a Principal (authenticated identity)
// to the Subject
if (debug) {
[Link]("\t\t[SampleLoginModule] " +
"added SamplePrincipal to Subject");
}
commitSucceeded = true;
return true;
}
}
/**
* This method is called if the LoginContext's
* overall authentication failed.
* (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* did not succeed).
*
* If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* <code>login</code> and <code>commit</code> methods),
* then this method cleans up any state that was originally saved.
*
* @exception LoginException if the abort fails.
*
/**
* Logout the user.
*
* This method removes the <code>SamplePrincipal</code>
* that was added by the <code>commit</code> method.
*
* @exception LoginException if the logout fails.
*
* @return true in all cases since this <code>LoginModule</code>
* should not be ignored.
*/
public boolean logout() throws LoginException {
[Link]().remove(userPrincipal);
succeeded = false;
succeeded = commitSucceeded;
username = null;
if (password != null) {
for (int i = 0; i < [Link]; i++)
password[i] = ' ';
password = null;
}
userPrincipal = null;
return true;
}
}
[Link]
package [Link];
import [Link];
/**
* This class implements the <code>Principal</code> interface
* and represents a Sample user.
*
* Principals such as this <code>SamplePrincipal</code>
* may be associated with a particular <code>Subject</code>
* to augment that <code>Subject</code> with an additional
* identity. Refer to the <code>Subject</code> class for more information
* on how to achieve this. Authorization decisions can then be based upon
* the Principals associated with a <code>Subject</code>.
*
* @see [Link]
* @see [Link]
*/
public class SamplePrincipal implements Principal, [Link] {
/**
* @serial
*/
private String name;
/**
* Create a SamplePrincipal with a Sample username.
*
* @param name the Sample username for this user.
*
* @exception NullPointerException if the <code>name</code>
* is <code>null</code>.
*/
public SamplePrincipal(String name) {
if (name == null)
throw new NullPointerException("illegal null input");
[Link] = name;
}
/**
* Return the Sample username for this <code>SamplePrincipal</code>.
*
* @return the Sample username for this <code>SamplePrincipal</code>
*/
public String getName() {
return name;
}
/**
* Return a string representation of this <code>SamplePrincipal</code>.
*
* @return a string representation of this <code>SamplePrincipal</code>.
*/
public String toString() {
return("SamplePrincipal: " + name);
}
/**
* Compares the specified Object with this <code>SamplePrincipal</code>
* for equality. Returns true if the given object is also a
* <code>SamplePrincipal</code> and the two SamplePrincipals
* have the same username.
*
* @param o Object to be compared for equality with this
* <code>SamplePrincipal</code>.
*
* @return true if the specified Object is equal equal to this
* <code>SamplePrincipal</code>.
*/
public boolean equals(Object o) {
if (o == null)
return false;
if (this == o)
return true;
if ([Link]().equals([Link]()))
return true;
return false;
}
/**
* Return a hash code for this <code>SamplePrincipal</code>.
*
* @return a hash code for this <code>SamplePrincipal</code>.
*/
public int hashCode() {
return [Link]();
}
}
See Appendix B: JAAS Login Configuration File for information as to what a login configuration
file is, what it contains, and how to specify which login configuration file should be used.
Sample {
[Link] required debug=true;
};
This entry is named "Sample" and that is the name that our tutorial application, SampleAcn,
uses to refer to this entry. The entry specifies that the LoginModule to be used to do the user
authentication is the SampleLoginModule in the [Link] package and that this
SampleLoginModule is required to "succeed" in order for authentication to be considered
successful. The SampleLoginModule succeeds only if the name and password supplied by the
user are the one it expects ("testUser" and "testPassword", respectively).
The SampleLoginModule also defines a "debug" option that can be set to true as shown. If this
option is set to true, SampleLoginModule outputs extra information about the progress of
authentication. A LoginModule can define as many options as it wants. The LoginModule
documentation should specify the possible option names and values you can set in your
configuration file.
Note
If you use a single equals sign (=) with the [Link] system
property (instead of a double equals sign (==)), then the configurations specified by
both this system property and the [Link] file are used.
You will be prompted for your user name and password, and the SampleLoginModule specified
in the login configuration file will check to ensure these are correct. The SampleLoginModule
expects testUser for the user name and testPassword for the password.
You will see some messages output by SampleLoginModule as a result of the debug option
being set to true in the login configuration file. Then, if your login is successful, you will see the
following message output by SampleAcn:
Authentication succeeded!
If the login is not successful (for example, if you misspell the password), you will see
Authentication failed:
followed by a reason for the failure. For example, if you mistype the password, you may see a
message like the following:
Authentication failed:
Password Incorrect
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
Most browsers install a security manager, so applets typically run under the scrutiny of a
security manager. Applications, on the other hand, do not, since a security manager is not
automatically installed when an application is running. Thus an application, like our SampleAcn
application, by default has full access to resources.
To run an application with a security manager, simply invoke the interpreter with a -
[Link] argument included on the command line.
If you try invoking SampleAcn with a security manager but without specifying any policy file, you
will get the following (unless you have a default policy setup elsewhere that grants the required
permissions or grants AllPermission):
% java -[Link] \
-[Link]==sample_jaas.config [Link]
Exception in thread "main" [Link]:
access denied (
[Link] [Link])
As you can see, you get an AccessControlException, because we haven't created and
used a policy file granting our code the permission that is required in order to be allowed to
create a LoginContext.
Here are the complete steps required in order to be able to run our SampleAcn application with
a security manager installed. You can skip the first five steps if you have already done them, as
described in Running the Code.
1. Place the following file into a directory:
• sample_jass.config login configuration file (see The Login Configuration File for
the JAAS Authentication Tutorial)
2. Create a subdirectory named sample of that top-level directory, and place the following
into it (note the SampleAcn and MyCallbackHandler classes, both in [Link],
are in a package named sample):
• [Link] application source file
3. Create a subdirectory of the sample directory and name it module. Place the following
into it (note the SampleLoginModule class is in a package named [Link]):
• [Link] source file
4. Create another subdirectory of the sample directory and name it principal. Place the
following into it (note the SamplePrincipal class is in a package named
[Link]):
• [Link] source file
5. While in the top-level directory, compile [Link], [Link], and
[Link]:
javac sample/[Link] sample/module/[Link] sample/
principal/[Link]
(Type all that on one line.)
6. Create a JAR file containing [Link] and [Link]:
jar -cvf [Link] sample/[Link] sample/[Link]
(Type all that on one line.) This command creates a JAR file, [Link], and places
the [Link] and [Link] files inside it.
7. Create a JAR file containing [Link] and [Link]:
jar -cvf [Link] sample/module/[Link] sample/principal/
[Link]
LoginContext lc =
new LoginContext("Sample",
new MyCallbackHandler());
permission [Link]
"[Link]";
The [Link] file also needs to be granted a permission. The documentation for a
LoginModule should tell you what permissions it needs to be granted. In the case of
SampleLoginModule, it needs a [Link] with target
modifyPrincipals in order to populate a Subject with a Principal:
permission [Link]
"modifyPrincipals";
Copy the policy file [Link] to the same directory as that in which you stored
[Link], etc. The policy file contains the following grant statement to grant
[Link] (in the current directory) its required permission:
The policy file also contains the following grant statement to grant [Link] (also in
the current directory) its required permission:
Note: Policy files and the structure of entries within them are described in Default Policy
Implementation and Policy File Syntax. Permissions are described in Permissions in the
JDK.
Execute the SampleAcn application, specifying
a. by an appropriate -classpath clause that classes should be searched for in the
[Link] and [Link] JAR files,
b. by -[Link] that a security manager should be installed,
c. by -[Link]==[Link] that the policy file to be used is
[Link], and
Note
Use the double equals sign (==) with the [Link] property with
care as it overrides the built-in JDK policy file, which grants a set of default
permissions that are designed to provide a secure, out-of-the-box configuration for
the JDK. Overriding this policy may result in unexpected behavior (JDK code may
not be granted the right permissions) and should only be done by experienced
users.
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
The following are the full commands to use for Windows, Linux, and macOS. The only
difference is that on Windows systems you use semicolons to separate class path items,
while you use colons for that purpose on Linux and macOS.
Here is the full command for Windows:
Type all that on one line. Multiple lines are used here for legibility. If the command is too
long for your system, you may need to place it in a .bat file (for Windows) or a .sh file (for
Linux and macOS) and then run that file to execute the command.
Since the specified policy file contains an entry granting the code the required permissions,
execution should proceed without any exceptions indicating a required permission was not
granted. You will be prompted for a user name and password (use testUser and
testPassword), and the SampleLoginModule specified in the login configuration file will
check the name and password. If your login is successful, you will see the message
Authentication succeeded! and if not, you will see Authentication failed: followed by
a reason for the failure.
[Link]
permission [Link]
"[Link]";
};
This grants the code in the [Link] file, located in the current directory, the specified
permission. (No signer is specified, so it doesn't matter whether the code is signed or not.)
JAAS authorization augments the existing code-centric access controls with new user-centric
access controls. Permissions can be granted based not just on what code is running but also
on who is running it.
When an application uses JAAS authentication to authenticate the user (or other entity such as
a service), a Subject is created as a result. The purpose of the Subject is to represent the
Permissions can be granted in the policy to specific Principals. After the user has been
authenticated, the application can associate the Subject with the current access control
context. For each subsequent security-checked operation (a local file access, for example), the
Java runtime will automatically determine whether the policy grants the required permission
only to a specific Principal and if so, the operation will be allowed only if the Subject
associated with the access control context contains the designated Principal.
where each of the signer, codeBase and Principal fields is optional and the order between
the fields doesn't matter.
A Principal field looks like the following:
That is, it is the word Principal (where case doesn't matter) followed by the (fully qualified)
name of a Principal class and a principal name.
The type of Principal placed in the Subject created by the basic authentication mechanism
used by this tutorial is SamplePrincipal, so that is what should be used as the
Principal_class part of our grant statement's Principal designation. User names for
SamplePrincipals are of the form name, and the only user name accepted for this tutorial is
testUser, so the principal_name designation to use in the grant statement is testUser.
It is possible to include more than one Principal field in a grant statement. If multiple
Principal fields are specified, then the permissions in that grant statement are granted only if
the Subject associated with the current access control context contains all of those
Principals.
To grant the same set of permissions to different Principals, create multiple grant statements
where each lists the permissions and contains a single Principal field designating one of the
Principals.
The policy file for this tutorial includes one grant statement with a Principal field:
This specifies that the indicated permissions are granted to the specified Principal executing
the code in [Link]. (Note: the SamplePrincipal class is in the [Link]
package.)
• [Link] is exactly the same as the [Link] application file from the
JAAS Authentication Tutorial tutorial except for the additional code needed to call
[Link].
• [Link] contains the SampleAction class. This class implements
PrivilegedAction and has a run method that contains all the code we want to be
executed with Principal-based authorization checks.
• [Link] is the class specified by the tutorial's login configuration file
(see The Login Configuration File for the JAAS Authorization Tutorial) as the class
implementing the desired underlying authentication. SampleLoginModule's user
authentication consists of simply verifying that the name and password specified by the
user have specific values. This class was also used by the JAAS Authentication Tutorial
tutorial and will not be discussed further here.
• [Link] is a sample class implementing the
[Link] interface. It is used by SampleLoginModule. This class was
also used by the JAAS Authentication tutorial and will not be discussed further here.
The [Link] and [Link] files were also used in the JAAS
Authentication Tutorial tutorial, so they are not described further here. The following sections
describe the other source files
[Link]
Like SampleAcn, the SampleAzn class instantiates a LoginContext lc and calls its login
method to perform the authentication. If successful, the authenticated Subject (which
includes a SamplePrincipal representing the user) is obtained by calling the
LoginContext's getSubject method:
After providing the user some information about the Subject, such as which Principals it
has, the main method then calls [Link], passing it the authenticated
Subject mySubject, a PrivilegedAction (SampleAction) and a null
AccessControlContext, as described in the following.
The doAsPrivileged method invokes execution of the run method in the PrivilegedAction
action (SampleAction) to initiate execution of the rest of the code, which is considered to be
executed on behalf of the Subject mySubject.
[Link]
package sample;
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
/**
* This Sample application attempts to authenticate a user
* and executes a SampleAction as that user.
*
* If the user successfully authenticates itself,
* the username and number of Credentials is displayed.
*/
public class SampleAzn {
/**
* Attempt to authenticate the user.
*
* @param args input arguments for this application. These are ignored.
*/
public static void main(String[] args) {
// attempt authentication
[Link]();
[Link]("Authentication failed:");
[Link](" " + [Link]());
try {
[Link]().sleep(3000);
} catch (Exception e) {
// ignore
}
}
}
[Link]("Authentication succeeded!");
[Link](0);
}
}
/**
* A CallbackHandler implemented by the application.
*
* This application is text-based. Therefore it displays information
* to the user using the OutputStreams [Link] and [Link],
* and gathers input from the user using the InputStream [Link].
*/
class MyCallbackHandler implements CallbackHandler {
/**
* Invoke an array of Callbacks.
*
* @param callbacks an array of <code>Callback</code> objects which
contain
* the information requested by an underlying security
* service to be retrieved or displayed.
*
* @exception [Link] if an input or output error occurs. <p>
*
* @exception UnsupportedCallbackException if the implementation of this
* method does not support one or more of the Callbacks
* specified in the <code>callbacks</code> parameter.
*/
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
[Link]([Link]());
[Link]();
[Link]((new BufferedReader
(new InputStreamReader([Link]))).readLine());
} else {
[Link]
[Link] contains the SampleAction class. This class implements
[Link] and has a run method that contains all the code we want to
be executed as the Subject mySubject. For this tutorial, we will perform three operations, each
of which cannot be done unless code has been granted required permissions. We will:
• Read and print the value of the [Link] system property,
• Read and print the value of the [Link] system property, and
• Determine whether or not a file named [Link] exists in the current directory.
Here is the code:
[Link]
package sample;
import [Link];
import [Link];
/**
* This is a Sample PrivilegedAction implementation, designed to be
* used with the Sample application.
*
*/
public class SampleAction implements PrivilegedAction {
/**
* This Sample PrivilegedAction performs the following operations:
* <ul>
* <li>Access the System property, <i>[Link]</i></li>
* <li>Access the System property, <i>[Link]</i></li>
* <li>Access the file, <i>[Link]</i></li>
* </ul>
*
* @return <code>null</code> in all cases.
*
* @exception SecurityException if the caller does not have permission
* to perform the operations listed previously.
*/
public Object run() {
[Link]("\nYour [Link] property: "
+[Link]("[Link]"));
Sample {
[Link] required debug=true;
};
This entry is named Sample and that is the name that both our tutorial applications SampleAcn
and SampleAzn use to refer to it. The entry specifies that the LoginModule to be used to do
the user authentication is the SampleLoginModule in the [Link] package and that this
SampleLoginModule is required to "succeed" in order for authentication to be considered
successful. The SampleLoginModule succeeds only if the name and password supplied by the
user are the one it expects (testUser and testPassword, respectively).
The SampleLoginModule also defines a debug option that can be set to true as shown. If
this option is set to true, SampleLoginModule outputs extra information about the progress
of authentication.
In order to call the doAsPrivileged method of the Subject class, you need to have a
[Link] with target "doAsPrivileged".
Assuming the SampleAzn class is placed in a JAR file named [Link], these
permissions can be granted to the SampleAzn code via the following grant statement in the
policy file:
We need to grant these permissions to the code in [Link], which we will place in
a JAR file named [Link]. However, for this particular grant statement we want to
grant the permissions not just to the code but to a specific user executing the code, to
demonstrate how to restrict access to a particular user.
Thus, as explained in How Do You Make Principal-Based Policy File Statements?, our grant
statement looks like the following:
[Link]
Warning
The Security Manager and APIs related to it have been deprecated and are
subject to removal in a future release. There is no replacement for the
Security Manager. See JEP 411 for discussion and alternatives.
Note
Use the double equals sign (==) with the [Link] property with
care as it overrides the built-in JDK policy file, which grants a set of default
permissions that are designed to provide a secure, out-of-the-box configuration for
the JDK. Overriding this policy may result in unexpected behavior (JDK code may
not be granted the right permissions) and should only be done by experienced
users.
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
The following are the full commands to use for Windows, Linux, and macOS. The only
difference is that on Windows you use semicolons to separate class path items, while you
use colons for that purpose on Linux and macOS.
Here is the full command for Windows:
-[Link]==[Link]
-[Link]==sample_jaas.config [Link]
Type the full command on one line. Multiple lines are used here for legibility. If the
command is too long for your system, you may need to place it in a .bat file (for
Windows) or a .sh file (for Linux and macOS) and then run that file to execute the
command.
You will be prompted for a user name and password (use testUser and testPassword),
and the SampleLoginModule specified in the login configuration file will check the name and
password. If your login is successful, you will see the message Authentication
succeeded! and if not, you will see Authentication failed: followed by a reason for the
failure.
Once authentication is successfully completed, the rest of the program (in SampleAction)
will be executed on behalf of you, the user, requiring you to have been granted appropriate
permissions. The [Link] policy file grants you the required permissions, so you
will see a display of the values of your [Link] and [Link] system properties and a
statement as to whether or not you have a file named [Link] in the current directory.
Related Documentation
This document assumes you have already read the following:
• Java Authentication and Authorization Service (JAAS) Reference Guide
It also discusses various classes and interfaces in the JAAS API. See the Javadoc API
documentation for the JAAS API specification for more detailed information:
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link].x500
The following packages contain supported LoginModule examples:
• [Link]
• [Link]
• [Link]
• [Link]
The following tutorials for JAAS authentication and authorization can be run by everyone:
• JAAS Authentication Tutorial
• JAAS Authorization Tutorial
Similar tutorials for JAAS authentication and authorization, but which demonstrate the use of a
Kerberos LoginModule and thus which require a Kerberos installation, can be found at
• JAAS Authentication Tutorial
• JAAS Authorization Tutorial
These two tutorials are a part of Introduction to JAAS and Java GSS-API Tutorials that utilize
Kerberos as the underlying technology for authentication and secure communication.
Introduction to LoginModule
Authentication technology providers must implement the LoginModule interface.
LoginModules are plugged in under applications to provide a particular type of authentication.
The Subject represents the user or service currently being authenticated and is updated by a
LoginModule with relevant Principals and credentials if authentication succeeds.
LoginModules use the CallbackHandler to communicate with users (to prompt for user names
and passwords, for example), as described in the login method description. Note that the
CallbackHandler may be null. A LoginModule that requires a CallbackHandler to authenticate
the Subject may throw a LoginException if it was initialized with a null CallbackHandler.
LoginModules optionally use the shared state to share information or data among themselves.
The LoginModule-specific options represent the options configured for this LoginModule in
the login Configuration. The options are defined by the LoginModule itself and control the
behavior within it. For example, a LoginModule may define options to support debugging/
testing capabilities. Options are defined using a key-value syntax, such as debug=true. The
LoginModule stores the options as a Map so that the values may be retrieved using the key.
Note that there is no limit to the number of options a LoginModule chooses to define.
The calling application sees the authentication process as a single operation invoked via a call
to the LoginContext's login method. However, the authentication process within each
LoginModule proceeds in two distinct phases. In the first phase of authentication, the
LoginContext's login method invokes the login method of each LoginModule specified in the
Configuration. The login method for a LoginModule performs the actual authentication
(prompting for and verifying a password for example) and saves its authentication status as
private state information. Once finished, the LoginModule's login method returns true (if it
succeeded) or false (if it should be ignored), or it throws a LoginException to specify a failure.
In the failure case, the LoginModule must not retry the authentication or introduce delays. The
responsibility of such tasks belongs to the application. If the application attempts to retry the
authentication, each LoginModule's login method will be called again.
In the second phase, if the LoginContext's overall authentication succeeded (calls to the
relevant required, requisite, sufficient and optional LoginModules' login methods succeeded),
then the commit method for each LoginModule gets invoked. (For an explanation of the
LoginModule flags required, requisite, sufficient and optional, please consult the
Configuration documentation and Appendix B: JAAS Login Configuration File in the JAAS
Reference Guide.) The commit method for a LoginModule checks its privately saved state to
see if its own authentication succeeded. If the overall LoginContext authentication succeeded
and the LoginModule's own authentication succeeded, then the commit method associates the
relevant Principals (authenticated identities) and credentials (authentication data such as
cryptographic keys) with the Subject.
Note
It is possible for LoginModule implementations not to have any end-user
interactions. Such LoginModules would not need to access the callback package.
2. Determine what configuration options you want to make available to the user, who
specifies configuration information in whatever form the current Configuration
implementation expects (for example, in files). For each option, decide the option name
and possible values.
For example, if a LoginModule may be configured to consult a particular authentication
server host, decide on the option's key name ("auth_server", for example), as well as the
possible server hostnames valid for that option ("server_one.[Link]" and
"server_two.[Link]", for example).
• initialize
• login
• commit
• abort
• logout
In addition to these methods, a LoginModule implementation must provide a public
constructor with no arguments. This allows for its proper instantiation by a LoginContext.
Note that if no constructor is provided in your LoginModule implementation, a default no-
argument constructor is automatically inherited from the Object class.
Note
If you don't implement the LoginModule interface, then a LoginException will be
thrown when you try to use your login module.
[Link] Method
The initialize method is called to initialize the LoginModule with the relevant authentication
and state information.
This method is called by a LoginContext immediately after this LoginModule has been
instantiated, and prior to any calls to its other public methods. The method implementation
should store away the provided arguments for future use.
The initialize method may additionally peruse the provided sharedState to determine what
additional authentication state it was provided by other LoginModules, and may also traverse
through the provided options to determine what configuration options were specified to affect
the LoginModule's behavior. It may save option values in variables for future use.
The following is a list of options commonly supported by LoginModules. Note that the
following is simply a guideline. Modules are free to support a subset (or none) of the following
options.
• tryFirstPass - If true, the first LoginModule in the stack saves the password entered,
and subsequent LoginModules also try to use it. If authentication fails, the
LoginModules prompt for a new password and retry the authentication.
• useFirstPass - If true, the first LoginModule in the stack saves the password entered,
and subsequent LoginModules also try to use it. LoginModules do not prompt for a
new password if authentication fails (authentication simply fails).
• tryMappedPass - If true, the first LoginModule in the stack saves the password entered,
and subsequent LoginModules attempt to map it into their service-specific password. If
authentication fails, the LoginModules prompt for a new password and retry the
authentication.
• useMappedPass - If true, the first LoginModule in the stack saves the password entered,
and subsequent LoginModules attempt to map it into their service-specific password.
LoginModules do not prompt for a new password if authentication fails (authentication
simply fails).
• moduleBanner - If true, then when invoking the CallbackHandler, the LoginModule
provides a TextOutputCallback as the first Callback, which describes the
LoginModule performing the authentication.
• debug - If true, instructs a LoginModule to output debugging information.
The initialize method may freely ignore state or options it does not understand, although it
would be wise to log such an event if it does occur.
Note that the LoginContext invoking this LoginModule (and the other configured
LoginModules, as well), all share the same references to the provided Subject and
sharedState. Modifications to the Subject and sharedState will, therefore, be seen by all.
[Link] Method
This method implementation should perform the actual authentication. For example, it may
cause prompting for a user name and password, and then attempt to verify the password
against a password database. Another example implementation may inform the user to insert
their finger into a fingerprint reader, and then match the input fingerprint against a fingerprint
database.
If your LoginModule requires some form of user interaction (retrieving a user name and
password, for example), it should not do so directly. That is because there are various ways of
communicating with a user, and it is desirable for LoginModules to remain independent of the
different types of user interaction. Rather, the LoginModule's login method should invoke the
handle method of the CallbackHandler interface passed to the initialize method to
perform the user interaction and set appropriate results, such as the user name and password.
The LoginModule passes the CallbackHandler an array of appropriate Callbacks, for example
a NameCallback for the user name and a PasswordCallback for the password, and the
CallbackHandler performs the requested user interaction and sets appropriate values in the
Callbacks. For example, to process a NameCallback, the CallbackHandler may prompt for a
name, retrieve the value from the user, and call the NameCallback's setName method to store
the name.
The authentication process may also involve communication over a network. For example, if
this method implementation performs the equivalent of a kinit in Kerberos, then it would need
to contact the KDC. If a password database entry itself resides in a remote naming service,
then that naming service needs to be contacted, perhaps via the Java Naming and Directory
Interface (JNDI). Implementations might also interact with an underlying operating system. For
example, if a user has already logged into an operating system like Solaris, Linux, macOS, or
Windows, this method might simply import the underlying operating system's identity
information.
The login method should
1. Determine whether or not this LoginModule should be ignored. One example of when it
should be ignored is when a user attempts to authenticate under an identity irrelevant to
this LoginModule (if a user attempts to authenticate as root using NIS, for example). If this
LoginModule should be ignored, login should return false. Otherwise, it should do the
following:
2. Call the CallbackHandler handle method if user interaction is required.
3. Perform the authentication.
4. Store the authentication result (success or failure).
5. If authentication succeeded, save any relevant state information that may be needed by
the commit method.
6. Return true if authentication succeeds, or throw a LoginException such as
FailedLoginException if authentication fails.
Note that the login method implementation should not associate any new Principal or
credential information with the saved Subject object. This method merely performs the
authentication, and then stores away the authentication result and corresponding
authentication state. This result and state will later be accessed by the commit or abort
method. Note that the result and state should typically not be saved in the sharedState Map, as
they are not intended to be shared with other LoginModules.
An example of where this method might find it useful to store state information in the
sharedState Map is when LoginModules are configured to share passwords. In this case, the
entered password would be saved as shared state. By sharing passwords, the user only enters
the password once, and can still be authenticated to multiple LoginModules. The standard
conventions for saving and retrieving names and passwords from the sharedState Map are the
following:
• [Link] - Use this as the shared state map key for saving/
retrieving a name. The value should be a String.
• [Link] - Use this as the shared state map key for saving/
retrieving a password. The value should be a char array.
If authentication fails, the login method should not retry the authentication. This is the
responsibility of the application. Multiple LoginContext login method calls by an application
are preferred over multiple login attempts from within [Link]().
[Link] Method
The commit method is called to commit the authentication process. This is phase 2 of
authentication when phase 1 succeeds. It is called if the LoginContext's overall authentication
succeeded (that is, if the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
LoginModules succeeded.)
This method should access the authentication result and corresponding authentication state
saved by the login method.
If the authentication result denotes that the login method failed, then this commit method
should remove/destroy any corresponding state that was originally saved.
If the saved result instead denotes that this LoginModule's login method succeeded, then the
corresponding state information should be accessed to build any relevant Principal and
credential information. Such Principals and credentials should then be added to the Subject
stored away by the initialize method.
After adding Principals and credentials, dispensable state fields should be destroyed
expeditiously. Likely fields to destroy would be user names and passwords stored during the
authentication process.
The commit method should save private state indicating whether the commit succeeded or
failed.
The following chart depicts what a LoginModule's commit method should return. The different
boxes represent the different situations that may occur. For example, the top-left corner box
depicts what the commit method should return if both the previous call to login succeeded and
the commit method itself succeeded.
[Link] Method
The abort method is called to abort the authentication process. This is phase 2 of
authentication when phase 1 fails. It is called if the LoginContext's overall authentication
failed.
This method first accesses this LoginModule's authentication result and corresponding
authentication state saved by the login (and possibly commit) methods, and then clears out
and destroys the information. Sample state to destroy would be user names and passwords.
If this LoginModule's authentication attempt failed, then there shouldn't be any private state to
clean up.
The following charts depict what a LoginModule's abort method should return. This first chart
assumes that the previous call to login succeeded. For instance, the abort method should
return TRUE if both the previous call to login and commit succeeded, and the abort method
itself also succeeded.
The second chart depicts what a LoginModule's abort method should return, assuming that
the previous call to login failed. For instance, the abort method should return FALSE if the
previous call to login failed, the previous call to commit succeeded, and the abort method
itself also succeeded.
[Link] Method
This method removes Principals, and removes/destroys credentials associated with the
Subject during the commit operation. This method should not touch those Principals or
credentials previously existing in the Subject, or those added by other LoginModules.
If the Subject has been marked read-only (the Subject's isReadOnly method returns true),
then this method should only destroy credentials associated with the Subject during the
commit operation (removing the credentials is not possible). If the Subject has been marked as
read-only and the credentials associated with the Subject during the commit operation are not
destroyable (they do not implement the Destroyable interface), then this method may throw a
LoginException.
The logout method should return true if logout succeeds, or otherwise throw a
LoginException.
Step 6a: Place Your LoginModule and Application Code in JAR Files
Place your LoginModule and application code in separate JAR files, in preparation for
referencing the JAR files in the policy in Step 6b: Set LoginModule and Application JAR File
Permissions. Here is a sample command for creating a JAR file:
This command creates a JAR file with the specified name containing the specified classes.
If your LoginModule and/or application performs security-sensitive tasks that will trigger
security checks (making network connections, reading or writing files on a local disk, etc.), it
will need to be granted the required permissions if it is run while a security manager is
installed; see Permissions in the JDK.
Since LoginModules usually associate Principals and credentials with an authenticated
Subject, some types of permissions a LoginModule will typically require are
AuthPermissions with target names "modifyPrincipals", "modifyPublicCredentials", and
"modifyPrivateCredentials".
The following is a sample statement granting permissions to a LoginModule whose code is in
[Link]. Such a statement could appear in a policy file. In this example, the [Link] file is
assumed to be in the /localWork directory.
Note
Since a LoginModule is always invoked within an [Link]
call, it should not have to call doPrivileged itself. If it does, it may inadvertently open
up a security hole. For example, a LoginModule that invokes the application-provided
CallbackHandler inside a doPrivileged call opens up a security hole by permitting
the application's CallbackHandler to gain access to resources it would otherwise not
have been able to access.
The default Configuration implementation from Oracle reads configuration information from
configuration files, as described in ConfigFile.
Create a configuration file to be used for testing. For example, to configure the previously-
mentioned hypothetical IBM LoginModule for an application, the configuration file might look
like this:
AppName {
[Link] REQUIRED debug=true;
};
where AppName should be whatever name the application uses to refer to this entry in the login
configuration file. The application specifies this name as the first argument to the LoginContext
constructor.
You could run the application and specify the configuration file via the following:
Type all that on one line. Multiple lines are used here for legibility.
To specify a policy file named [Link] and run the application with a security manager
installed, do the following:
Be sure to also include testing using different installation options (e.g., placing the LoginModule
on the class path or module path) and execution environments (with or without a security
manager running). In particular, in order to ensure your LoginModule works when a security
manager is installed and the LoginModule, you need to test such an installation and execution
environment, after granting required permissions, as described in Step 6b: Set LoginModule
and Application JAR File Permissions.
1. If you find during testing that your LoginModule or application needs modifications, make
the modifications, recompile (Step 5: Compile the LoginModule and Application).
2. Place the updated code in a JAR file (Step 6a: Place Your LoginModule and Application
Code in JAR Files).
3. If needed fix or add to the permissions (Step 6b: Set LoginModule and Application JAR File
Permissions).
4. If needed modify the login configuration file (Step 6c: Create a Configuration Referencing
the LoginModule).
5. Re-run the application and repeat these steps as needed.
Java Generic Security Services (Java GSS-API) is used for securely exchanging messages
between communicating applications.
Introduction to JAAS and Java GSS-API Tutorials is a series of tutorials demonstrating various
aspects of the use of Java Authentication and Authorization Service (JAAS) and Java GSS-
API.
Single Sign-on Using Kerberos in Java discusses how to use Single Sign-On based on the
Kerberos V5 protocol.
Advanced Security Programming in Java SE Authentication, Secure Communication and
Single Sign-On shows you how to use the Java SE GSS APIs to build applications that
authenticate their users, communicate securely with other applications and services, and
configure your applications in a Kerberos environment to achieve Single Sign-On.
The Kerberos 5 GSS-API Mechanism describes and lists security features regarding Java
Generic Security Services (Java GSS) for Kerberos 5.
1. Use of Java GSS-API for Secure Message Exchanges Without JAAS Programming
Demonstrates the use of the Java GSS-API for secure message exchanges between a
client application and a server application.
2. JAAS Authentication
Explains how an application can authenticate users using JAAS.
3. JAAS Authorization
Explains how to enforce user-based access controls using JAAS.
4. Use of JAAS Login Utility
Describes a utility program that authenticates a user using JAAS and executes any
application as that user. The appropriate user-based access controls are enforced while
the application executes. This utility, as a convenience, essentially performs the operations
described in the JAAS Authentication and JAAS Authorization tutorials on your behalf.
Therefore it is possible to skip directly to this tutorial if you do not need to know how to
perform JAAS authentication and authorization directly.
5. Use of JAAS Login Utility and Java GSS-API for Secure Message Exchanges
The most comprehensive tutorial. The Login utility is used to authenticate a service user
and to start up a server application as that user. The Login utility is also used to
authenticate a client user and to start up a client application as that user. Finally the client
and server applications, on behalf of their authenticated client and service users, exchange
secure messages using the Java GSS-API.
6. More Things You Can Do with Java GSS-API and JAAS
Shows additional operations the server application in the previous tutorial can perform
once communication has been established with the client application.
All applications in all tutorials in this series utilize Kerberos Version 5 as the underlying
technology for authentication and secure communication. See Kerberos Requirements. The
term "Kerberos" used throughout the tutorials is meant to refer to Kerberos Version 5.
Java GSS-API, on the other hand, is a token-based API that relies on the application to do
the communication. This means that the application can use TCP sockets, UDP
datagrams, or any other channel that will allow it to transport Java GSS-API generated
tokens. If your application has varying communication protocol needs, then Java GSS-API
might be more appropriate for you. Java GSS-API can read and write its tokens using input
and output streams. However, you will need to set up the streams yourself.
3. Credential Delegation
Java GSS-API allows the client to delegate its credentials to the server when using
Kerberos. If your application will be deployed in a multi-tier environment where
intermediaries need to impersonate clients when talking to backend layers, Java GSS-API
might be more appropriate for you.
4. Selective Encryption
Because Java GSS-API is token-based, you can choose to selectively encrypt certain
messages but not all. If your application needs to intersperse plaintext and ciphertext
messages, Java GSS-API might be more appropriate for you.
5. Protocol Requirements
JSSE provides implementations of the TLS protocol including TLS version 1.3 and TLS
version 1.2. Java GSS-API provides an implementation of the GSS-API framework defined
in Generic Security Service API Version 2: Java Bindings Update (RFC 5653), as well as
an implementation of the Kerberos Version 5 mechanism defined in The Kerberos Version
5 GSS-API Mechanism (RFC 1964). (On Microsoft Windows platforms, this may be known
as SSPI with Kerberos.) Some servers such as HTTPS servers will require you to use TLS,
in which case JSSE will be appropriate for you. Other servers such as LDAP servers using
SASL might need GSS-API with Kerberos, in which case Java GSS-API will be appropriate
for you.
For this tutorial, we will not have the client and server perform JAAS authentication, nor will we
have them use the Login utility. Instead, we will rely on setting the system property
[Link] to false, which allows us to relax the restriction
of requiring a GSS mechanism to obtain necessary credentials from an existing Subject, set up
by JAAS. See The useSubjectCredsOnly System Property.
Note
This is a simplified introductory tutorial. For example, we do not include any policy files
or run the sample code using a security manager. In real life, code using Java GSS-
API should be run with a security manager, so that security-sensitive operations would
not be allowed unless the required permissions were explicitly granted.
There is another tutorial, Use of JAAS Login Utility and Java GSS-API for Secure Message
Exchanges, that is just like the tutorial you are reading except that it utilizes the Login utility,
policy files, and a more complex login configuration file. A login configuration file (see Appendix
B: JAAS Login Configuration File), required whenever JAAS authentication is done, specifies
the desired authentication module.
As with all tutorials in this series, the underlying technology used to support authentication and
secure communication for the applications in this tutorial is Kerberos V5. See Kerberos
Requirements.
• Overview of the Client and Server Applications
• The SampleClient and SampleServer Code
• Kerberos User and Service Principal Names
• The Login Configuration File
• The useSubjectCredsOnly System Property
• Running the SampleClient and SampleServer Programs
If you want to first see the tutorial code in action, you can skip directly to Running the
SampleClient and SampleServer Programs and then go back to the other sections to learn
more.
b. Attempts a socket connection with the SampleServer, using the host and port it was
passed as arguments.
3. The socket connection is accepted by SampleServer and both applications initialize a
DataInputStream and a DataOutputStream from the socket input and output
streams, to be used for future data exchanges.
4. SampleClient and SampleServer each instantiate a GSSContext and follow a protocol for
establishing a shared context that will enable subsequent secure data exchanges.
5. SampleClient and SampleServer can now securely exchange messages.
6. When SampleClient and SampleServer are done exchanging messages, they perform
clean-up operations.
The actual code and further details are presented in the following sections.
Note
The Java GSS-API classes utilized by these programs (GSSManager, GSSContext,
GSSName, GSSCredential, MessageProp, and Oid) are found in the
[Link] package.
1. A service principal name – The name of the Kerberos principal that represents
SampleServer (see Kerberos User and Service Principal Names).
2. A host name – The machine on which SampleServer is running.
3. A port number – The port number of the port on which SampleServer listens for
connections.
Here is the code for reading the command-line arguments:
if ([Link] < 3) {
[Link]("Usage: java <options> Login SampleClient "
+ " <servicePrincipal> <hostName> <port>");
[Link](-1);
}
• A local port number – The port number used by SampleServer for listening for connections
with clients. This number should be the same as the port number specified when running
the SampleClient program.
Here is the code for reading the command-line argument:
if ([Link] != 1) {
[Link](
"Usage: java <options> Login SampleServer <localPort>");
[Link](-1);
}
DataInputStream inStream =
new DataInputStream([Link]());
DataOutputStream outStream =
new DataOutputStream([Link]());
The ServerSocket can then wait for and accept a connection from a client, and then initialize a
DataInputStream and a DataOutputStream for future data exchanges with the client :
DataInputStream inStream =
new DataInputStream([Link]());
DataOutputStream outStream =
new DataOutputStream([Link]());
The accept method waits until a client (in our case, SampleClient) requests a connection on
the host and port of the SampleServer, which SampleClient does via
When the connection is requested and established, the accept method returns a new Socket
object bound to a new port. The server can communicate with the client over this new socket
and continue to listen for other client connection requests on the ServerSocket bound to the
original port. Thus, a server program typically has a loop which can handle multiple connection
requests.
The basic loop structure for our SampleServer is the following:
while (true) {
Client connections are queued at the original port, so with this program structure used by
SampleServer, the interaction with the first client making a connection has to complete before
the next connection can be accepted. The server could actually service multiple clients
simultaneously through the use of threads – one thread per client connection, as in
while (true) {
<accept a connection>;
<create a thread to handle the client>;
}
While Java GSS-API methods exist for preparing tokens to be exchanged between
applications, it is the responsibility of the applications to actually transfer the tokens between
them. So after the initiator has received a token from its call to initSecContext, it sends that
token to the acceptor. The acceptor calls acceptSecContext, passing it the token. The
acceptSecContext method may in turn return a token. If it does, the acceptor should send that
token to the initiator, which should then call initSecContext again and pass it this token. Each
time initSecContext or acceptSecContext returns a token, the application that called the
method should send the token to its peer and that peer should pass the token to its appropriate
method (acceptSecContext or initSecContext). This continues until the context is fully
established (which is the case when the context's isEstablished method returns true).
The context establishment code for our sample applications is described in the following:
• Context Establishment by SampleClient
• Context Establishment by SampleServer
The default GSSManager subclass is one whose create* methods (createContext, etc.)
return classes whose implementations support Kerberos as the underlying technology.
The GSSManager factory method for creating a context on the initiator's side has the following
signature:
The following sections describe the arguments, followed by the complete call to
createContext.
The second argument is an Oid. An Oid represents a Universal Object Identifier. Oids are
hierarchically globally-interpretable identifiers used within the GSS-API framework to identify
mechanisms and name types. The structure and encoding of Oids is defined in the
ISOIEC-8824 and ISOIEC-8825 standards. The Oid passed to the createName method is
specifically a name type Oid (not a mechanism Oid).
In GSS-API, string names are often mapped from a mechanism-independent format into a
mechanism-specific format. Usually, an Oid specifies what name format the string is in so that
the mechanism knows how to do this mapping. Passing in a null Oid indicates that the name
is already in a native format that the mechanism uses. This is the case for the server String; it
is in the appropriate format for a Kerberos Version 5 name. Thus, SampleClient passes a null
for the Oid. Here is the call:
Our tutorial will use Kerberos V5 as the security mechanism. The Oid for the Kerberos V5
mechanism is defined in RFC 1964 as "1.2.840.113554.1.2.2" so we create such an Oid:
GSSContext context =
[Link](serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
1. Mutual authentication. The context initiator is always authenticated to the acceptor. If the
initiator requests mutual authentication, then the acceptor is also authenticated to the
initiator.
2. Confidentiality. Requesting confidentiality means that you request the enabling of
encryption for the context method named wrap. Encryption is actually used only if the
MessageProp object passed to the wrap method requests privacy.
3. Integrity. This requests integrity for the wrap and getMIC methods. When integrity is
requested, a cryptographic tag known as a Message Integrity Code (MIC) will be
generated when calling those methods. When getMIC is called, the generated MIC
appears in the returned token. When wrap is called, the MIC is packaged together with the
message (the original message or the result of encrypting the message, depending on
whether confidentiality was applied) all as part of one token. You can subsequently verify
the MIC against the message to ensure that the message has not been modified in transit.
The SampleClient code for making these requests on the GSSException context is the
following:
After the context is established, the client must explicitly check the context states by calling the
accesor methods, like getMutualAuthState, getConfState, or getIntegState, and
destroy the security context if any of them do not match the desired state.
Note
When using the default GSSManager implementation and the Kerberos mechanism,
these requests will always be granted.
while (![Link]()) {
The GSSManager factory method for creating a context on the acceptor's side has the
following signature:
If you pass null for the GSSCredential argument, as SampleServer does, the default
credentials are used. The context is instantiated via the following:
while (![Link]()) {
if ([Link]())
[Link]("Mutual authentication took place!");
The signature for the wrap method called by SampleClient is the following:
You pass wrap a message (in inBuf), the offset into inBuf where the message begins
(offset), and the length of the message (len). You also pass a MessageProp, which is used
to indicate the desired QOP (Quality-of-Protection) and to specify whether or not privacy
(encryption) is desired. A QOP value selects the cryptographic integrity and encryption (if
requested) algorithm(s) to be used. The algorithms corresponding to various QOP values are
specified by the provider of the underlying mechanism. For example, the values for Kerberos
V5 are defined in RFC 1964 in section 4.2. It is common to specify 0 as the QOP value to
request the default QOP.
The wrap method returns a token containing the message and a cryptographic Message
Integrity Code (MIC) over it. The message placed in the token will be encrypted if the
MessageProp indicates privacy is desired. You do not need to know the format of the returned
token; it should be treated as opaque data. You send the returned token to your peer
application, which calls the unwrap method to "unwrap" the token to get the original message
and to verify its integrity.
getMIC
If you simply want to get a token containing a cryptographic Message Integrity Code (MIC) for
a supplied message, you call getMIC. A sample reason you might want to do this is to confirm
with your peer that you both have the same data, by just transporting a MIC for that data
without incurring the cost of transporting the data itself to each other.
The signature for the getMIC method called by SampleServer is the following:
You pass getMIC a message (in inMsg), the offset into inMsg where the message begins
(offset), and the length of the message (len). You also pass a MessageProp, which is used
to indicate the desired QOP (Quality-of-Protection). It is common to specify 0 as the QOP
value to request the default QOP.
If you have a token created by getMIC and the message used to calculate the MIC (or a
message purported to be the message on which the MIC was calculated), you can call the
verifyMIC method to verify the MIC for the message. If the verification is successful (that is, if
a GSSException is not thrown), it proves that the message is exactly the same as it was
when the MIC was calculated. A peer receiving a message from an application typically
expects a MIC as well, so that they can verify the MIC and be assured the message has not
been modified or corrupted in transit. Note: If you know ahead of time that you will want the
MIC as well as the message then it is more convenient to use the wrap and unwrap methods.
But there could be situations where the message and the MIC are received separately.
The signature for the verifyMIC corresponding to the getMIC shown previously is the following:
This verifies the MIC contained in the inToken (of length tokLen, starting at offset tokOffset)
over the message contained in inMsg (of length msgLen, starting at offset msgOffset). The
MessageProp is used by the underlying mechanism to return information to the caller, such as
the QOP indicating the strength of protection that was applied to the message.
5. SampleServer sends the token returned by getMIC (which contains the MIC) to
SampleClient.
6. SampleClient calls verifyMIC to verify that the MIC sent by SampleServer is a valid MIC
for the original message.
SampleClient Code to Encrypt the Message and Send It
The SampleClient code for encrypting a message, calculating a MIC for it, and sending the
result to SampleServer is the following:
/*
* The first MessageProp argument is 0 to request
* the default Quality-of-Protection.
* The second argument is true to request
* privacy (encryption of the message).
*/
MessageProp prop = new MessageProp(0, true);
/*
* Encrypt the data and send it across. Integrity protection
* is always applied, irrespective of encryption.
*/
token = [Link](messageBytes, 0, [Link],
prop);
[Link]("Will send wrap token of size "
+ [Link]);
[Link]([Link]);
[Link](token);
[Link]();
Note
Here, the integrity check is expected to succeed. But note that in general if an integrity
check fails, it signifies that the message was changed in transit. If the unwrap method
encounters an integrity check failure, it throws a GSSException with major error code
GSSException.BAD_MIC.
/*
* Create a MessageProp which unwrap will use to return
* information such as the Quality-of-Protection that was
* applied to the wrapped token, whether or not it was
* encrypted, etc. Since the initial MessageProp values
* are ignored, it doesn't matter what they are set to.
*/
MessageProp prop = new MessageProp(0, false);
/*
* Read the token. This uses the same token byte array
* as that used during context establishment.
*/
token = new byte[[Link]()];
[Link]("Will read token of size "
+ [Link]);
[Link](token);
Next, SampleServer generates a MIC for the decrypted message and sends it to
SampleClient. This is not really necessary but simply illustrates generating a MIC on the
decrypted message, which should be exactly the same as the original message SampleClient
wrapped and sent to SampleServer. When SampleServer generates this and sends it to
SampleClient, and SampleClient verifies it, this proves to SampleClient that the decrypted
message SampleServer has is in fact exactly the same as the original message from
SampleClient.
/*
* First reset the QOP of the MessageProp to 0
* to ensure the default Quality-of-Protection
* is applied.
*/
[Link](0);
/*
* Recall messageBytes is the byte array containing
* the original message and prop is the MessageProp
* already instantiated by SampleClient.
*/
[Link](token, 0, [Link],
messageBytes, 0, [Link],
prop);
Clean Up
When SampleClient and SampleServer have finished exchanging messages, they need to
perform cleanup operations. Both contain the following code to
• close the socket connection and
• release system resources and cryptographic information stored in the context object and
then invalidate the context.
[Link]();
[Link]();
A server program like SampleServer is typically considered to offer a "service" and to be run on
behalf of a particular "service principal." A service principal name for SampleServer is needed
in several places:
• When you run SampleServer, and SampleClient attempts a connection to it, the underlying
Kerberos mechanism will attempt to authenticate to the Kerberos KDC. It prompts you to
log in. You should log in as the appropriate service principal.
• When you run SampleClient, one of the arguments is the service principal name. This is
needed so SampleClient can initiate establishment of a security context with the
appropriate service.
• If the SampleClient and SampleServer programs were run with a security manager (they're
not for this tutorial), the client and server policy files would each require a
ServicePermission with name equal to the service principal name and action equal to
"initiate" or "accept" (for initiating or accepting establishment of a security context).
Throughout this document, and in the accompanying login configuration file,
service_principal@your_realm, is used as a placeholder to be replaced by the actual name
to be used in your environment. Any Kerberos principal can actually be used for the service
principal name. So for the purposes of trying out this tutorial, you could use your user
name as both the client user name and the service principal name.
In a production environment, system administrators typically like servers to be run as specific
principals only and may assign a particular name to be used. Often the Kerberos-style service
principal name assigned is of the form
service_name/machine_name@realm;
For example, an nfs service run on a machine named raven in the realm named KRBNT-
[Link] could have the service principal name
nfs/raven@[Link]
Such multi-component names are not required, however. Single-component names, just like
those of user principals, can be used. For example, an installation might use the same ftp
service principal ftp@realm for all ftp servers in that realm, while another installation might
have different ftp principals for different ftp servers, such as ftp/host1@realm and ftp/
host2@realm on machines host1 and host2, respectively.
The [Link] login configuration file used for this tutorial is the following:
[Link] {
[Link].Krb5LoginModule required;
};
[Link] {
[Link].Krb5LoginModule required storeKey=true
};
The Krb5LoginModule succeeds only if the attempt to log in to the Kerberos KDC as a
specified entity is successful. When running SampleClient or SampleServer, the user will be
prompted for a name and password.
The SampleServer entry storeKey=true indicates that a secret key should be calculated from
the password provided during login and it should be stored in the private credentials of the
Subject created as a result of login. This key is subsequently utilized during mutual
authentication when establishing a security context between SampleClient and SampleServer.
The Krb5LoginModule Javadoc API documentation describes the configuration options that
the Krb5LoginModule class supports.
1. Copy the following files into a directory accessible by the machine on which you will run
SampleServer:
• The [Link] source file.
• The [Link] login configuration file.
2. Compile [Link]:
javac [Link]
1. Copy the following files into a directory accessible by the machine on which you will run
SampleClient:
• The [Link] source file.
• The [Link] login configuration file.
2. Compile [Link]:
javac [Link]
Execute SampleServer
It is important to execute SampleServer before SampleClient because SampleClient will try to
make a socket connection to SampleServer and that will fail if SampleServer is not yet running
and accepting socket connections.
To execute SampleServer, be sure to run it on the machine it is expected to be run on. This
machine name (host name) is specified as an argument to SampleClient. The service principal
name appears in several places, including the login configuration file and the policy files.
Go to the directory in which you have prepared SampleServer for execution. Execute
SampleServer, specifying
The only argument required by SampleServer is one specifying the port number to be used for
listening for client connections. Choose a high port number unlikely to be used for anything
else. An example would be something like 4444.
The following is the full command to use for both Microsoft Windows and Solaris, Linux, and
macOS systems.
Note
Important: In this command, you must replace <port_number> with an
appropriate port number, <your_realm> with your Kerberos realm, and
<your_kdc> with your Kerberos KDC.
-[Link]=<your_krb5.conf_file>
java -[Link]=<your_realm>
-[Link]=<your_kdc>
-[Link]=false
-[Link]=[Link]
SampleServer <port_number>
The full command should appear on one line (or, on Solaris, Linux, or macOS, on multiple lines
where each line but the last is terminated with " \" indicating that there is more to come).
Multiple lines are used here just for legibility. Since this command is very long, you may need
to place it in a .bat file (for Windows) or a .sh file (for Solaris, Linux, or macOS) and then run
that file to execute the command.
The SampleServer code will listen for socket connections on the specified port. When
prompted, type the Kerberos name and password for the service principal. The underlying
Kerberos authentication mechanism specified in the login configuration file will log the service
principal into Kerberos.
For login troubleshooting suggestions, see Troubleshooting.
Execute SampleClient
To execute SampleClient, first go to the directory in which you have prepared SampleClient
for execution. Execute SampleClient, specifying
Note
If you use a single equals sign (=) with the [Link] system
property (instead of a double equals sign (==)), then the configurations specified by
both this system property and the [Link] file are used.
The SampleClient arguments are (1) the Kerberos name of the service principal that
represents SampleServer (see Kerberos User and Service Principal Names, (2) the name of
the host (machine) on which SampleServer is running, and (3) the port number on which
SampleServer is listening for client connections.
The following is the full command to use for both Windows and Solaris, Linux, and macOS
systems.
Note
Important: In this command, you must replace <service_principal>, <host>,
<port_number>, <your_realm>, and <your_kdc> with appropriate values (and note
that the port number must be the same as the port number passed as an argument to
SampleServer). These values need not be placed in quotes.
java -[Link]=<your_realm>
-[Link]=<your_kdc>
-[Link]=false
-[Link]=[Link]
SampleClient <service_principal> <host> <port_number>
Type the full command on one line. Multiple lines are used here for legibility. As with the
command for executing SampleServer, if the command is too long to type directly into your
command window, place it in a .bat file (Windows) or a .sh file (Solaris, Linux, and macOS) and
then execute that file.
When prompted, type your Kerberos user name and password. The underlying Kerberos
authentication mechanism specified in the login configuration file will log you into Kerberos.
The SampleClient code requests a socket connection with SampleServer. Once SampleServer
accepts the connection, SampleClient and SampleServer establish a shared context and then
exchange messages as described in this tutorial.
For login troubleshooting suggestions, see Troubleshooting.
JAAS Authentication
JAAS can be used for two purposes:
• for authentication of users, to reliably and securely determine who is currently executing
Java code, regardless of whether the code is running as an application, an applet, a bean,
or a servlet; and
• for authorization of users to ensure they have the access control rights (permissions)
required to do the actions performed.
This section provides a basic tutorial for the authentication component. The authorization
component will be described in the JAAS Authorization tutorial.
JAAS authentication is performed in a pluggable fashion. This permits Java applications to
remain independent from underlying authentication technologies. New or updated technologies
can be plugged in without requiring modifications to the application itself. An implementation
for a particular authentication technology to be used is determined at runtime. The
implementation is specified in a login configuration file. The authentication technology used for
this tutorial is Kerberos. (See Kerberos Requirements.)
The rest of this tutorial consists of the following sections:
1. The Authentication Tutorial Code
2. The Login Configuration
3. Running the Code
4. Running the Code with a Security Manager
If you want to first see the tutorial code in action, you can skip directly to Running the Code
and then go back to the other sections to learn about coding and configuration file details.
Instantiating a LoginContext
In order to authenticate a user, you first need a [Link].
Here is the basic way to instantiate a LoginContext:
import [Link].*;
. . .
LoginContext lc =
new LoginContext(<config file entry name>,
<CallbackHandler to be used for user interaction>);
and here is the specific way our tutorial code does the instantiation:
import [Link].*;
import [Link];
. . .
LoginContext lc =
new LoginContext("JaasSample",
new TextCallbackHandler());
[Link]();
The LoginContext's login method then calls methods in the Krb5LoginModule to perform
the login and authentication. The Krb5LoginModule will utilize the TextCallbackHandler
to obtain the user name and password. Then the Krb5LoginModule will use this information
to get the user credentials from the Kerberos KDC. See the Kerberos reference
documentation.
If authentication is successful, the Krb5LoginModule populates the Subject with (1) a
Kerberos Principal representing the user and (2) the user's credentials (TGT).
The calling application can subsequently retrieve the authenticated Subject by calling the
LoginContext's getSubject method, although doing so is not necessary for this tutorial.
See Appendix B: JAAS Login Configuration File for information as to what a login configuration
file is, what it contains, and how to specify which login configuration file should be used.
JaasSample {
[Link].Krb5LoginModule required;
};
This entry is named JaasSample and that is the name that our tutorial application, JaasAcn,
uses to refer to this entry. The entry specifies that the LoginModule to be used to do the user
authentication is the Krb5LoginModule in the [Link] package and
that this Krb5LoginModule is required to "succeed" in order for authentication to be
considered successful. The Krb5LoginModule succeeds only if the name and password
supplied by the user are successfully used to log the user into the Kerberos KDC.
See the Krb5LoginModule Javadoc API documentation for information about all the possible
options that can be passed to Krb5LoginModule.
javac [Link]
Note
Be sure to replace <your_realm> with your Kerberos realm, and <your_kdc> with
your Kerberos KDC.
java -[Link]=<your_realm>
-[Link]=<your_kdc>
-[Link]=[Link] JaasAcn
Type all that on one line. Multiple lines are used here for legibility.
You will be prompted for your Kerberos user name and password, and the underlying Kerberos
authentication mechanism specified in the login configuration file will log you into Kerberos. If
your login is successful, you will see the following message:
Authentication succeeded!
If the login is not successful (for example, if you misspell your password), you will see
Authentication failed:
followed by a reason for the failure. For example, if you mistype your user name, you may see
a message like the following (where the formatting is slightly modified here to increase
legibility):
Authentication failed:
Kerberos Authentication Failed:
[Link]:
KrbException: Client not found in Kerberos database
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
When a Java program is run with a security manager installed, the program is not allowed to
access resources or otherwise perform security-sensitive operations unless it is explicitly
granted permission (see Permissions in the JDK to do so by the security policy in effect. The
permission must be granted by an entry in a policy file (see Default Policy Implementation and
Policy File Syntax).
Most browsers install a security manager, so applets typically run under the scrutiny of a
security manager. Applications, on the other hand, do not, since a security manager is not
automatically installed when an application is running. Thus an application, like our JaasAcn
application, by default has full access to resources.
To run an application with a security manager, simply invoke the interpreter with a -
[Link] argument included on the command line.
If you try invoking JaasAcn with a security manager but without specifying any policy file, you
will get the following (unless you have a default policy setup elsewhere that grants the required
permissions or grants AllPermission):
% java -[Link] \
-[Link]=<your_realm> \
-[Link]=<your_kdc> \
-[Link]=[Link] JaasAcn
Exception in thread "main" [Link]:
access denied (
[Link] [Link])
As you can see, you get an AccessControlException, because we haven't created and
used a policy file granting our code the permission that is required in order to be allowed to
create a LoginContext.
Here are the complete steps required in order to be able to run our JaasAcn application with a
security manager installed. You can skip the first two steps if you have already done them, as
described in Running the Code.
1. Place the [Link] application source file and the [Link] login configuration
file into a directory.
2. Compile [Link]:
javac [Link]
This command creates a JAR file, [Link], and places the [Link] file inside
it.
4. Create a policy file granting the code in the JAR file the required permission.
The permission that is needed by code attempting to instantiate a LoginContext is a
[Link] with target createLoginContext.<entry name>.
Here, <entry name> refers to the name of the login configuration file entry that the
application references in its instantiation of LoginContext. The name used by our
LoginContext lc =
new LoginContext("JaasSample",
new TextCallbackHandler());
permission [Link]
"[Link]";
Copy the policy file [Link] to the same directory as that in which you stored
[Link], etc. This is a text file containing the following grant statement to grant
[Link] (in the current directory) the required permission:
Note: Policy files and the structure of entries within them are described in Default Policy
Implementation and Policy File Syntax. Permissions are described in Permissions in the
JDK.
5. Execute the JaasAcn application, specifying
a. by an appropriate -classpath clause that classes should be searched for in the
[Link] JAR file,
b. by -[Link] that a security manager should be installed,
c. by -[Link]=<your_realm> that your Kerberos realm is the one
specified. For example, if your realm is [Link]'d put -
[Link]=[Link].
d. by -[Link]=<your_kdc> that your Kerberos KDC is the one
specified. For example, if your KDC is [Link]'d put -
[Link]=[Link].
e. by -[Link]=[Link] that the policy file to be used is
[Link], and
f. by -[Link]=[Link] that the login configuration file to
be used is [Link].
Note
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
Note
Be sure to replace <your_realm> with your Kerberos realm, and <your_kdc>
with your Kerberos KDC.
Type all that on one line. Multiple lines are used here for legibility. If the command is too
long for your system, you may need to place it in a .bat file (for Windows) or a .sh file (for
Linux and macOS) then run that file to execute the command.
Since the specified policy file contains an entry granting the code the required permission,
JaasAcn will be allowed to instantiate a LoginContext and continue execution. You will
be prompted for your Kerberos user name and password, and the underlying Kerberos
authentication mechanism specified in the login configuration file will log you into Kerberos.
If your login is successful, you will see the message "Authentication succeeded!" and if not,
you will see "Authentication failed:" followed by a reason for the failure.
For login troubleshooting suggestions, see Troubleshooting.
JAAS Authorization
This tutorial expands the program and policy file developed in the JAAS Authentication tutorial
to demonstrate the JAAS authorization component, which ensures the authenticated caller has
the access control rights (permissions) required to do subsequent security-sensitive
operations. Since the authorization component requires that the user authentication first be
completed, please read the JAAS Authentication tutorial first if you have not already done so.
The rest of this tutorial consists of the following sections:
• What is JAAS Authorization?
• How Is JAAS Authorization Performed?
– How Do You Make Principal-Based Policy File Statements?
– How Do You Associate a Subject with an Access Control Context?
• The Authorization Tutorial Code
• The Login Configuration File
• The Policy File
• Running the Authorization Tutorial Code
If you want to first see the tutorial code in action, you can skip directly to Running the
Authorization Tutorial Code and then go back to the other sections to learn more.
This grants the code in the [Link] file, located in the current directory, the specified
permission. (No signer is specified, so it doesn't matter whether the code is signed or not.)
JAAS authorization augments the existing code-centric access controls with new user-centric
access controls. Permissions can be granted based not just on what code is running but also
on who is running it.
When an application uses JAAS authentication to authenticate the user (or other entity such as
a service), a Subject is created as a result. The purpose of the Subject is to represent the
authenticated user. A Subject is comprised of a set of Principals, where each Principal
represents an identity for that user. For example, a Subject could have a name Principal
("Susan Smith") and a Social Security Number Principal ("987-65-4321"), thereby
distinguishing this Subject from other Subjects.
Permissions can be granted in the policy to specific Principals. After the user has been
authenticated, the application can associate the Subject with the current access control
context. For each subsequent security-checked operation, (a local file access, for example),
the Java runtime will automatically determine whether the policy grants the required permission
only to a specific Principal and if so, the operation will be allowed only if the Subject
associated with the access control context contains the designated Principal.
where each of the signer, codeBase and Principal fields is optional and the order between the
fields doesn't matter.
A Principal field looks like the following:
That is, it is the word "Principal" (where case doesn't matter) followed by the (fully qualified)
name of a Principal class and a principal name.
A Principal class is a class that implements the [Link] interface.
All Principal objects have an associated name that can be obtained by calling their getName
method. The format used for the name is dependent on each Principal implementation.
The type of Principal placed in the Subject created by the Kerberos authentication
mechanism used by this tutorial is [Link], so
that is what should be used as the Principal_class part of our grant statement's Principal
designation. User names for KerberosPrincipals are of the form name@realm. Thus, if the user
name is mjones and the realm is [Link], the full principal_name designation to
use in the grant statement is mjones@[Link].
It is possible to include more than one Principal field in a grant statement. If multiple Principal
fields are specified, then the permissions in that grant statement are granted only if the
Subject associated with the current access control context contains all of those Principals.
To grant the same set of permissions to different Principals, create multiple grant statements
where each lists the permissions and contains a single Principal field designating one of the
Principals.
The policy file for this tutorial includes one grant statement with a Principal field:
where you substitute your Kerberos user name (complete with "@" and realm) for
your_user_name@your_realm. This specifies that the indicated permissions are granted to the
specified principal executing the code in [Link].
[Link]
[Link] is exactly the same as the [Link] code used in the previous tutorial
except with three statements added at the end of the main method, after the authentication is
done. These statements result in (1) association of a Subject representing the authenticated
user with the current access control context and (2) execution of the code in the run method of
SampleAction. Associating the Subject with the access control context enables security-
sensitive operations in the SampleAction run method (and any code it invokes directly or
indirectly) to be executed if a Principal representing the authenticated user is granted the
required permissions in the current policy.
Like [Link], [Link] instantiates a LoginContext lc and calls its login method
to perform the authentication. If successful, the authenticated Subject (which includes a
Principal representing the user) is obtained by calling the LoginContext's getSubject
method:
The main method then calls [Link], passing it the authenticated Subject
mySubject, a PrivilegedAction (SampleAction) and a null AccessControlContext, as
described in the following.
The doAsPrivileged method invokes execution of the run method in the PrivilegedAction
action (SampleAction) to initiate execution of the rest of the code, which is considered to be
executed on behalf of the Subject mySubject.
[Link]
[Link] contains the SampleAction class. This class implements
[Link] and has a run method that contains all the code we want to
be executed as the Subject mySubject. For this tutorial, we will perform three operations, each
of which cannot be done unless code has been granted required permissions. We will:
• Read and print the value of the [Link] system property,
• Read and print the value of the [Link] system property, and
• Determine whether or not a file named [Link] exists in the current directory.
JaasSample {
[Link].Krb5LoginModule required;
};
This entry is named "JaasSample" and that is the name that both our tutorial applications
JaasAcn and JaasAzn use to refer to it. The entry specifies that the LoginModule to be used
to do the user authentication is the Krb5LoginModule in the [Link]
package and that this Krb5LoginModule is required to "succeed" in order for authentication
to be considered successful. The Krb5LoginModule succeeds only if the name and
password supplied by the user are successfully used to log the user into the Kerberos KDC.
In order to call the doAsPrivileged method of the Subject class, you need to have a
[Link] with target doAsPrivileged.
Assuming the JaasAzn class is placed in a JAR file named [Link], these permissions
can be granted to the JaasAzn code via the following grant statement in the policy file:
We need to grant these permissions to the code in [Link], which we will place in
a JAR file named [Link]. However, for this particular grant statement we want to
grant the permissions not just to the code but to a specific user executing the code, to
demonstrate how to restrict access to a particular user.
Thus, as explained in How Do You Make Principal-Based Policy File Statements?, our grant
statement looks like the following:
You substitute your Kerberos user name (complete with "@" and realm) for
your_user_name@your_realm. For example, if your user name is mjones and your realm is
[Link], you would use mjones@[Link].
Warning
The Security Manager and APIs related to it have been deprecated and are
subject to removal in a future release. There is no replacement for the
Security Manager. See JEP 411 for discussion and alternatives.
Note
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
The following are the full commands to use for Windows, Linux, and macOS. The only
difference is that on Windows you use semicolons to separate classpath items, while you
use colons for that purpose on gLinux, and macOS.
Note
Be sure to replace <your_realm> with your Kerberos realm, and <your_kdc>
with your Kerberos KDC.
Type the full command on one line. Multiple lines are used here for legibility. If the
command is too long for your system, you may need to place it in a .bat file (for Windows)
or a .sh file (for Linux and macOS) and then run that file to execute the command.
You will be prompted for your Kerberos user name and password, and the underlying
Kerberos authentication mechanism specified in the login configuration file will log you into
Kerberos. If your login is successful, you will see the message "Authentication succeeded!"
and if not, you will see "Authentication Failed."
For login troubleshooting suggestions, see Troubleshooting.
Once authentication is successfully completed, the rest of the program (in SampleAction)
will be executed on behalf of you, the user, requiring you to have been granted appropriate
permissions. The [Link] policy file grants you the required permissions, so you
will see a display of the values of your [Link] and [Link] system properties and a
statement as to whether or not you have a file named [Link] in the current directory.
Application Requirements
In order to utilize the Login utility, your application code does not need anything special. All you
need is for the entry point of your application to be the main method of a class you write, as
usual.
The way to invoke Login such that it will authenticate the user and then instantiate MyAction to
invoke your application is the following:
where <AppName> is your application's top-level class name and <app arguments> are any
arguments required by your application. See Running the Sample Program with the Login
Utility for the full command used for this tutorial.
users). One way of specifying the policy is by grant statements in a policy file. See The Policy
File for more information.
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
If you use the Login utility to invoke your application, then you will need to grant it various
permissions, as described in Permissions Required by the Login and MyAction Classes.
The only difference is the name used for the entry. In the previous tutorial we used the name
"JaasSample", since that is the name used by the JaasAzn class to look up the entry. When
you use the Login utility with your application, it expects the name for your login configuration
file entry to be the same as the name of your top-level application class. That application class
for this tutorial is named "Sample" so that must also be the name of the login configuration file
entry. Thus the login configuration file looks like the following:
Sample {
[Link].Krb5LoginModule required;
};
The "required" indicates that login using the Krb5LoginModule is required to "succeed" in
order for authentication to be considered successful. The Krb5LoginModule succeeds only if
the name and password supplied by the user are successfully used to log the user into the
Kerberos KDC.
See the Krb5LoginModule Javadoc API documentation for information about all the possible
options that can be passed to Krb5LoginModule.
The Sample code does three operations for which permissions are required. It
We need to grant these permissions to the code in [Link], which we will place in a JAR
file named [Link]. However, our grant statement will grant the permissions not just to the
code but to a specific authenticated user executing the code. This illustrates how you can use
a Principal designation in a grant statement to restrict execution of security-sensitive
operations in code to a specific user rather than allowing the permissions to all users executing
the code.
Thus, as explained in JAAS Authorization, our grant statement looks like the following:
Note
Important: You must substitute your Kerberos user name (complete with "@"
and realm) for your_user_name@your_realm.
For example, if your user name is mjones and your realm is KRBNT-
[Link], you would use mjones@[Link].
Note that [Link] contains two classes and thus compiling [Link] creates
[Link] and [Link].
4. Create a JAR file named [Link] containing [Link] and [Link]:
Note
If you use a single equals sign (=) with the [Link]
system property (instead of a double equals sign (==)), then the configurations
specified by both this system property and the [Link] file are used.
You pass the name of your application (in this case, Sample) as an argument to Login. You
would then add as arguments any arguments required by your application, but in our case
Sample does not require any.
The following are the full commands to use for Windows, Solaris, Linux, and macOS. The
only difference is that on Windows you use semicolons to separate classpath items, while
you use colons for that purpose on Solaris, Linux, and macOS. Be sure to replace
<your_realm> with your Kerberos realm, and <your_kdc> with your Kerberos KDC.
Here is the full command for Windows:
Type the full command on one line. Multiple lines are used here for legibility. If the
command is too long for your system, you may need to place it in a .bat file (for Windows)
or a .sh file (for Solaris, Linux, and macOS) and then run that file to execute the command.
You will be prompted for your Kerberos user name and password, and the underlying
Kerberos login module specified in the login configuration file will log you into Kerberos.
Once authentication is successfully completed, the Sample code will be executed on behalf
of you, the user. The [Link] policy file grants you the required permissions, so you
will see a display of the values of your [Link] and [Link] system properties and a
statement as to whether or not you have a file named [Link] in the current directory.
For login troubleshooting suggestions, see Troubleshooting.
Use of JAAS Login Utility and Java GSS-API for Secure Message
Exchanges
This tutorial presents two sample applications to demonstrate the use of the Java GSS-API.
This API permits secure exchanges of messages between communicating applications. Here
are the sample client and server applications you'll need for this tutorial:
• [Link]
• [Link]
Note
This tutorial uses the same client and server applications as the Use of Java GSS-API
for Secure Message Exchanges Without JAAS Programming tutorial. In that tutorial,
JAAS (Java Authentication and Authorization Service) programming is not required.
Instead, you let the underlying mechanism decide how to get credentials.
This tutorial uses policy files and a more complex login configuration file. The programs are run
with a security manager; as a result, security-sensitive operations are not allowed unless the
required permissions were explicitly granted. This tutorial also demonstrates how JAAS
authorization adds user-centric access control that applies control based on who is running the
code – not just on what code is running.
• Before You Start: Recommended Reading
• Overview of the Client and Server Applications
• Kerberos User and Service Principal Names
• The Login Configuration File
• The Policy Files
• Running the SampleClient and SampleServer Programs
Each is invoked by executing the Login utility supplied with this tutorial and passing it as
arguments the name of the application (SampleClient or SampleServer), followed by the
arguments needed by the application. The Login utility uses a JAAS LoginContext to
authenticate the user using Kerberos. Finally, the Login utility invokes the main method of the
application class, in our case either SampleClient or SampleServer, and passes the
application its arguments.
Here is a summary of execution of the SampleClient and SampleServer applications:
1. Run the SampleServer application by running the Login utility and passing it as arguments
the name "SampleServer" followed by the arguments for the SampleServer program. The
Login utility prompts you for the password for the principal that SampleServer should run
as. (See Kerberos User and Service Principal Names.) After authentication is complete,
SampleServer is run it:
a. Reads its argument, the port number that it should listen on for client connections.
b. Creates a ServerSocket for listening for client connections on that port.
c. Listens for a connection.
2. Run the SampleClient application (possibly on a different machine), by running the Login
utility and passing it as arguments the name "SampleClient" followed by the arguments for
the SampleClient program. The Login utility prompts you for your Kerberos name and
password. After authentication is complete, SampleClient is run. It
a. Reads its arguments: (1) The name of the Kerberos principal that represents
SampleServer. (See Kerberos User and Service Principal Names.), (2) the name of the
host (machine) on which SampleServer is running, and (3) the port number on which
SampleServer listens for client connections.
b. Attempts a socket connection with the SampleServer, using the host and port it was
passed as arguments.
3. The socket connection is accepted by SampleServer and both applications initialize a
DataInputStream and a DataOutputStream from the socket input and output
streams, to be used for future data exchanges.
4. SampleClient and SampleServer each instantiate a GSSContext and establish a shared
context that will enable subsequent secure data exchanges.
5. SampleClient and SampleServer can now securely exchange messages.
6. When SampleClient and SampleServer are done exchanging messages, they perform
clean-up operations.
Note
Refer to the The SampleClient and SampleServer Code section of the Use of Java GSS-API
for Secure Message Exchanges Without JAAS Programming tutorial for a full discussion of the
code used in this tutorial.
A server program like SampleServer is typically considered to offer a "service" and to be run on
behalf of a particular "service principal." A service principal name for SampleServer is needed
in several places:
• When you run SampleServer you must log in as the appropriate service principal. The login
configuration file for this tutorial actually specifies the service principal name (as an option
to the Krb5LoginModule), so the JAAS authentication (done by the Login utility) just
asks you to specify the password for that service principal. If you specify the correct
password, the authentication is successful, a Subject is created containing a Principal
with the service principal name, and that Subject is associated with a new access control
context. The subsequently-executed code (the SampleServer code) is considered to be
executed on behalf of the specified principal.
• When you run SampleClient, one of the arguments is the service principal name. This is
needed so SampleClient can initiate establishment of a security context with the
appropriate service.
• The client and server policy files each require a ServicePermission with name equal to
the service principal name and action equal to "initiate" or "accept" (for initiating or
accepting establishment of a security context).
Throughout this document, and in the accompanying login configuration file and policy files,
service_principal@your_realm is used as a placeholder to be replaced by the actual name to
be used in your environment. Any Kerberos principal can actually be used for the service
principal name. So for the purposes of trying out this tutorial, you could use your user
name as both the client user name and the service principal name.
In a production environment, system administrators typically like servers to be run as specific
principals only and may assign a particular name to be used. Often the Kerberos-style service
principal name assigned is of the form
service_name/machine_name@realm;
For example, an nfs service run on a machine named "raven" in the realm named KRBNT-
[Link] could have the service principal name
nfs/raven@[Link]
Such multi-component names are not required, however. Single-component names, just like
those of user principals, can be used. For example, an installation might use the same ftp
service principal ftp@realm for all ftp servers in that realm, while another installation might
have different ftp principals for different ftp servers, such as ftp/host1@realm and ftp/
host2@realm on machines host1 and host2, respectively.
SampleClient {
[Link].Krb5LoginModule required;
};
SampleServer {
[Link].Krb5LoginModule required storeKey=true
principal="service_principal@your_realm";
};
Note that the name for each entry matches the respective class names for our two top-level
applications, SampleClient and SampleServer. Recall that this is also the name that is passed
to the Login utility that performs JAAS operations for the application. That utility expects the
name of the entry to be looked up in your login configuration file to be the same as the name it
is passed.
Both entries specify that Oracle's Kerberos V5 LoginModule must be used to successfully
authenticate the user. The Krb5LoginModule succeeds only if the attempt to log in to the
Kerberos KDC as a specified entity is successful. In the case of SampleClient, the user will be
prompted for their name and password. In the case of SampleServer, a name is already
supplied in this login configuration file (the specified principal) and the user running
SampleServer is just asked for the password for the entity specified by that name. They must
specify the correct password in order for authentication to succeed.
The SampleServer entry storeKey=true indicates that a secret key should be calculated from
the password provided during login and it should be stored in the private credentials of the
Subject created as a result of login. This key is subsequently utilized during mutual
authentication when establishing a security context between SampleClient and SampleServer.
The Krb5LoginModule has a principal option that can be used to specify that only the
specified principal (entity/user) should be logged in for the given program. Here, the
SampleClient entry does not specify a principal (although it could, if desired), so the user is
prompted for a user name and password and anyone with a valid user name and password
can run SampleClient. SampleServer, on the other hand, indicates a particular principal
because system administrators usually like servers to be run as specific principals only. In this
case, the user running SampleServer is prompted for that principal's password and must
supply the correct one in order for authentication to succeed.
Note that you must replace service_principal@your_realm with the name of the service
principal that represents SampleServer. (See Kerberos User and Service Principal Names.)
If the server has a keytab file containing secret keys, then use the following JAAS login entry:
SampleServer {
[Link].Krb5LoginModule required
principal="service_principal@your_realm"
storeKey=true useKeyTab=true keyTab=[Link]
isInitiator=false;
};
Because the keytab file already provides the keys, you will not be prompted for a password. If
the keytab file contains keys for more than one service principal and the server is designed to
act as all these service principals, then you can set the principal entry to the following:
principal=*
See the Krb5LoginModule Javadoc API documentation for information about all the possible
options that can be passed to Krb5LoginModule.
• opens a socket connection with the host machine running the SampleServer application.
• initiates establishment of a security context with SampleServer.
The permission required to open a socket connection is
You may replace the "*" with the hostname or IP address of the machine that SampleServer will
be running on.
The permission(s) required to initiate establishment of a security context will depend on the
underlying mechanism. This tutorial uses Kerberos as the underlying mechanism, and for that
two [Link] are required. A
ServicePermission contains a service principal name and an action (or list of actions). To
initiate establishment of a security context, you need two ServicePermissions with action
"initiate", whose names specify:
• the service principal name for the ticket granting service for your realm. Granting this
permission essentially allows the use of Kerberos as a client.
• the service principal name representing SampleServer. (See Kerberos User and Service
Principal Names.) Granting this permission allows you to interact with the service,
SampleServer, using Kerberos.
We want to grant the permissions to a specific authenticated user executing SampleClient, so
we specify both the SampleClient code location (in [Link]) and a Principal
designation indicating the user name and realm for the user (you, the person who will run
SampleClient). (See How Do You Make Principal-Based Policy File Statements? in JAAS
Authorization for information on policy file grant statements that include Principal
designations.)
Here is the basic form for the grant statement:
permission [Link]
"krbtgt/your_realm@your_realm",
"initiate";
permission [Link]
"service_principal@your_realm",
"initiate";
};
You must substitute your Kerberos user name (complete with "@" and realm) for
your_user_name@your_realm. For example, if your user name is mjones and your realm is
[Link], you would use mjones@KRBNT-
[Link].
You must also substitute your realm in krbtgt/your_realm@your_realm and the service
principal name for the service principal representing the server (see Kerberos User and
Service Principal Names for the service principal name for the service principal representing
the server for service_principal@your_realm. Suppose the former is krbtgt/KRBNT-
[Link]@[Link] and the latter is
sample/[Link]@[Link], and your user name
is as specified in the previous paragraph. Then the grant statement would be
permission [Link]
"krbtgt/[Link]@[Link]",
"initiate";
permission [Link]
"sample/[Link]@[Link]",
"initiate";
};
You may replace the "*" with the hostname or IP address of the machine that SampleClient will
be running on.
The permission required to accept establishment of a security context is
permission [Link]
"service_principal@your_realm",
"accept";
We want to grant the permissions to a specific authenticated user executing SampleServer (the
service principal considered to represent SampleServer), so we specify both the SampleServer
code location (in [Link]) and a Principal designation indicating the service
principal. Suppose this name is sample/[Link]@[Link].
Then the grant statement would be
permission [Link]
"sample/[Link]@[Link]", "accept";
};
1. Copy the following files into a directory accessible by the machine on which you will run
SampleServer:
• The [Link] source file.
• The [Link] source file.
• The [Link] login configuration file.
• The [Link] policy file.
2. Replace service_principal@your_realm in [Link] with the name of the service
principal representing SampleServer (see Kerberos User and Service Principal Names).
3. In both places it appears, replace service_principal@your_realm in [Link] with
the Kerberos name of the service principal that represents SampleServer. (The same
name as that used in the login configuration file.)
4. Compile [Link] and [Link]:
Note that [Link] contains two classes and thus compiling [Link] creates
[Link] and [Link].
5. Create a JAR file named [Link] containing [Link] and [Link]:
1. Copy the following files into a directory accessible by the machine on which you will run
SampleClient:
• The [Link] source file.
Execute SampleServer
It is important to execute SampleServer before SampleClient because SampleClient will try to
make a socket connection to SampleServer and that will fail if SampleServer is not yet running
and accepting socket connections.
To execute SampleServer, be sure to run it on the machine it is expected to be run on. This
machine name (host name) is specified as an argument to SampleClient. The service principal
name appears in several places, including the login configuration file and the policy files.
Go to the directory in which you have prepared SampleServer for execution. Execute the Login
class, specifying
• by an appropriate -classpath clause that classes should be searched for in the [Link]
and [Link] JAR files,
• by -[Link] that a security manager should be installed,
• by -[Link]=<your_realm> that your Kerberos realm is the one
specified. For example, if your realm is [Link] you'd put -
[Link]=[Link].
• by -[Link]=<your_kdc> that your Kerberos KDC is the one specified.
For example, if your KDC is [Link] you'd put -
[Link]=[Link].
• by -[Link]=[Link] that the policy file to be used is
[Link], and
• by -[Link]=[Link] that the login configuration file to
be used is [Link].
Note
If you use a single equals sign (=) with the [Link] system
property (instead of a double equals sign (==)), then the configurations specified by
both this system property and the [Link] file are used.
You pass the name of your application (in this case, SampleServer) as an argument to Login.
You then add as arguments any arguments required by your application, which in the case of
SampleServer is a single argument specifying the port number to be used for listening for client
connections. Choose a high port number unlikely to be used for anything else. An example
would be something like 4444.
The following are the full commands to use for Windows and Solaris, Linux, and macOS. The
only difference is that Windows you use semicolons to separate class path items, while you
use colons for that purpose on Solaris, Linux, and macOS.
Note
Important: In these commands, you must replace <port_number> with an
appropriate port number, <your_realm> with your Kerberos realm, and
<your_kdc> with your Kerberos KDC.
Type the full command on one line. Multiple lines are used here for legibility. If the command is
too long for your system, you may need to place it in a .bat file (for Windows) or a .sh file (for
Solaris, Linux, and macOS) and then run that file to execute the command.
You will be prompted for the Kerberos password for the service principal. The underlying
Kerberos authentication mechanism specified in the login configuration file will log the service
principal into Kerberos. Once authentication is successfully completed, the SampleServer code
will be executed on behalf of the service principal. It will listen for socket connections on the
specified port.
Execute SampleClient
To execute SampleClient, go to the directory in which you have prepared SampleClient for
execution. Then execute the Login class, specifying
• by an appropriate -classpath clause that classes should be searched for in the [Link]
and [Link] JAR files,
• by -[Link] that a security manager should be installed,
• by -[Link]=<your_realm> that your Kerberos realm is the one
specified.
• by -[Link]=<your_kdc> that your Kerberos KDC is the one specified.
• by -[Link]=[Link] that the policy file to be used is
[Link], and
• by -[Link]=[Link] that the login configuration file to
be used is [Link].
Pass to Login the name of your application (SampleClient) followed by the arguments required
by SampleClient. The SampleClient arguments are (1) the Kerberos name of the service
principal that represents SampleServer (see Kerberos User and Service Principal Names, (2)
the name of the host (machine) on which SampleServer is running, and (3) the port number on
which SampleServer is listening for client connections.
The following are the full commands to use for Windows, Linux, and macOS.
Note
Important: In these commands, you must replace <service_principal>, <host>,
<port_number>, <your_realm>, and <your_kdc> with appropriate values (and note
that the port number must be the same as the port number passed as an argument to
SampleServer). These values need not be placed in quotes.
-[Link]=[Link]
Login SampleClient <service_principal> <host> <port_number>
Type the full command on one line. Multiple lines are used here for legibility. As with the
command for executing SampleServer, if the command is too long to type directly into your
command window, place it in a .bat file (Windows) or a .sh file (Linux and macOS) and then
execute that file.
When prompted, type your Kerberos user name and password. The underlying Kerberos
authentication mechanism specified in the login configuration file will log you into Kerberos.
Once authentication is successfully completed, the SampleClient code will be executed on
behalf of you. It will request a socket connection with SampleServer. Once SampleServer
accepts the connection, SampleClient and SampleServer establish a shared context and then
exchange messages as described in this tutorial.
For login troubleshooting suggestions, see Troubleshooting.
Basic Approach
How does the server "impersonate" the client to execute code on behalf of the user running the
client code? Essentially the same way the client code is set up to be run on behalf of that user.
All the server code needs to know is the user's principal name, which it can obtain from the
context established with the client.
Recall that JAAS authentication of the user executing the client code results in creation of a
Subject containing a Principal with the user (principal) name. The Subject is subsequently
associated with a new access control context (via a [Link] call from the
Login utility) and the client code is considered to be executed on behalf of the user;
subsequent access control decisions are based on whether or not that particular user,
executing the client code, is granted the required permissions.
The server code is similarly handled, except in that case the Principal specified for
authentication is typically a "service principal", not a user principal. Again, a Subject
containing a Principal with the specified principal name is created,
[Link] is called, and the server code is considered to be executed on behalf
of the specified principal; subsequent access control decisions are based on whether or not
that particular principal, executing the server code, is granted the required permissions.
Once the client and server have established a mutual context, the context initiator's name (the
client's principal name) can be determined by the following:
The context acceptor (the server) can use this name to construct a Subject containing a
Principal that represents the same entity. For example, you can construct such a Subject
with Oracle's JDK via the following:
Subject client =
[Link](clientGSSName, null);
The createSubject method creates a new Subject from the GSSName and GSSCredential
specified as arguments. If the server code is just going to execute code on behalf of the user in
the local JVM, the user's credentials are not required – and in fact cannot even be obtained
unless the client has delegated credentials to the server, as discussed in Using Credentials
Delegated from the Client. Since the credentials are not needed here, we pass a null for the
GSSCredential argument.
Note
Note: If you are not using Oracle's JDK, an alternative way to do this is to construct a
KerberosPrincipal instance as follows:
KerberosPrincipal principal =
new KerberosPrincipal([Link]());
Then use this principal to construct a new Subject or populate this principal in the
principal set of an existing Subject.
The code that the server would like to execute on behalf of the user should be initiated
from the run method of a class that implements [Link] (or
[Link]). That is, the code can either be in such
a run method or invoked from such a run method.
The server code can pass the Subject, along with an instance of the
PrivilegedAction (or PrivilegedExceptionAction), to
[Link] to execute the subsequent code, starting with the run
method in the PrivilegedAction, on behalf of the principal (user) in the specified
Subject.
For example, suppose the PrivilegedAction class is called ReadFileAction
and it takes as an argument a String with the principal name. You can create an
instance of this class by
[Link]
The [Link] file is exactly the same as the [Link] file from
the previous (Use of JAAS Login Utility and Java GSS-API for Secure Message Exchanges)
tutorial, except that after exchanging messages with the client, it has the following code to
perform a ReadFileAction as the client user:
[Link]("Impersonating client.");
/*
* Extract the KerberosPrincipal from the client GSSName and
* populate it in the principal set of a new Subject. Pass in a
* null for credentials since credentials will not be needed.
*/
GSSName clientGSSName = [Link]();
[Link]("clientGSSName: " + clientGSSName);
Subject client =
[Link](clientGSSName,
null);
/*
* Construct an action that will read a file meant only for the
* client
*/
String clientName = [Link]();
PrivilegedAction readFile =
new ReadFileAction(clientName);
/*
* Invoke the action via a doAsPrivileged. This allows the
* action to be executed as the client subject, and it also
* runs that code as privileged. This means that any permission
* checking that happens beyond this point applies only to
* the code being run as the client.
*/
[Link](client, readFile, null);
[Link]
The [Link] file contains the ReadFileAction class. Its constructor takes as
an argument a String for the name of the client user. The client user name is used to
construct a file name for a file from which ReadFileAction will attempt to read. The file name
will be:
./data/<name>_info.txt
where <name> is the client user name without its corresponding realm. For example, if the full
user name is mjones@[Link], then the file name is
./data/mjones_info.txt
Note
On Window, the forward slashes will be backward slashes.
The ReadFileAction run method reads the specified file and prints its contents.
[Link]
ReadFileAction attempts to read a file, which is a security-checked operation. Since
ReadFileAction is considered to be executed as the client user (Principal), the
appropriate permission must be granted not only to the ReadFileAction code itself, but to
the client Principal as well.
Assuming the ReadFileAction class is placed in a JAR file named [Link], and
the user principal name is mjones@[Link], this permission can be
granted via the following in a policy file:
The [Link] file is exactly the same as the [Link] file from the previous
(Use of JAAS Login Utility and Java GSS-API for Secure Message Exchanges) tutorial, except
that it grants the SampleServer code the [Link]
"doAsPrivileged" permission it needs in order to call the doAsPrivileged method, and it has
the following placeholder for granting the FilePermission shown previously:
You must substitute your Kerberos realm for your_realm, and your user name for
your_user_name in both your_user_name@your_realm and data/your_user_name_info.txt. If
you are working on Windows, you also replace the "/" in data/your_user_name_info.txt with
a "\".
javac [Link]
jar -cvf [Link] [Link]
javac [Link]
jar -cvf [Link] [Link]
Note
Important: In these commands, you must replace <port_number> with an
appropriate port number (a high port number such as 4444),
<your_realm> with your Kerberos realm, and <your_kdc> with your
Kerberos KDC.
-[Link]=[Link]
Login SampleServerImp <port_number>
As usual, type the full command on one line. Multiple lines are used here for legibility. If
the command is too long for your system, you may need to place it in a .bat file (for
Windows) or a .sh file (for Linux and macOS) and then run that file to execute the
command.
As when running SampleServer, you will be prompted for the Kerberos password for
the service principal under which SampleServerImp is expected to be run. The
Kerberos login module specified in the login configuration file will log the service
principal into Kerberos. Once authentication is successfully completed, the
SampleServerImp code will be executed on behalf of the service principal. It will listen
for socket connections on the specified port.
After you follow the "Prepare SampleClient for Execution" and "Execute
SampleClient" instructions as usual and perform the user login, the client code will
request a socket connection with SampleServerImp. Once SampleServerImp accepts
the connection, SampleClient and SampleServerImp establish a shared context and
then exchange messages as described in the previous tutorial.
After the message exchange, SampleServerImp determines the principal name of the
user executing the client code, creates a new Subject containing a Principal with
that name, and calls [Link] to execute the code in ReadFileAction
on behalf of the specified user. ReadFileAction reads the file named
your_user_name_info.txt (where your_user_name represents the actual user name)
in the data subdirectory of the current directory, and prints out its contents.
For login troubleshooting suggestions, see Troubleshooting.
[Link](true);
then this requests that the initiator's credentials be delegated to the acceptor during context
establishment.
Delegation of credentials from the initiator to the acceptor enables the acceptor to authenticate
itself as an agent or delegate of the initiator.
First, after context establishment, the acceptor must determine whether or not credential
delegation actually took place. It does so by calling the getCredDelegState method:
If credentials were delegated, the acceptor can obtain those credentials by calling the
getDelegCr method:
The resulting GSSCredential object can then be used to initiate subsequent GSS-API
contexts as a "delegate" of the initiator. For example, the server could authenticate as the
client to a backend server that cares more about who the original client was than who the
intermediate server is.
Acting as the client, the server can establish a connection with the backend server, establish a
joint security context, and exchange messages in basically the same manner that the client
and server did.
One way it could be done is that when the server calls the createContext method of a
GSSManager, it could pass createContext the delegated credentials instead of passing a
null.
Constrained Delegation
If constrained delegation is configured in a KDC server, then, on the server side, the
getCredDelegState() call might still return true and getDelegCred() would return
delegated credentials, depending on the KDC settings, even if the client has not called
requestCredDeleg(true).
permission [Link]
"\"service_principal@your_realm\"
\"krbtgt/your_realm@your_realm\"";
Note that DelegationPermission has a single target in quotes that contains two items,
both of which are quoted. Each inner quote is escaped by a "\". Thus the first item is
"service_principal@your_realm"
"krbtgt/your_realm@your_realm"
This basically gives the code executing on behalf of the client the permission to forward a
Kerberos ticket to the specified peer (service_principal), where the Kerberos ticket is meant
to avail service from krbtgt/your_realm@your_realm.
Substitute your realm for all places your_realm appears. Also substitute the service principal
name for the service principal representing the server for service_principal@your_realm.
(See Kerberos User and Service Principal Names in the previous tutorial.) Suppose your realm
is [Link] and the service principal is sample/
[Link]@[Link]. Then the permission could appear in a
policy file as
permission [Link]
"\"sample/[Link]@[Link]\"
\"krbtgt/[Link]@[Link]\"";
Kerberos Requirements
Kerberos Version 5 is used for both the authentication and secure communication aspects of
the client and server applications developed in this tutorial. The reader is assumed to already
be familiar with Kerberos. See the Kerberos reference documentation.
The JAAS framework, and the Kerberos mechanism required by the Java GSS-API methods,
are built into JDKs from all vendors. The Kerberos LoginModule required for the JAAS
authentication in this tutorial may not be available in all vendors' JDKs. We will be using the
LoginModule for Kerberos provided by Oracle's JDK.
In order to run the sample programs, you will need access to a Kerberos installation. As
described in the following sections, you may also need a [Link] Kerberos configuration file
and an indication as to where that file is located.
As with all Kerberos installations, a Kerberos Key Distribution Center (KDC) is required. It
needs to contain the user name and password you will use to be authenticated to Kerberos.
Note
A KDC implementation is part of a Kerberos installation and not a part of the JDK.
[Link]
[Link]
If you set one of these properties you must set them both.
Also note that if you set these properties, then no cross-realm authentication is possible unless
a [Link] file is also provided from which the additional information required for cross-realm
authentication may be obtained.
If you set values for these properties, then they override the default realm and KDC values
specified in [Link] (if such a file is found). The [Link] file is still consulted if values for
items other than the default realm and KDC are needed. If no [Link] file is found, then the
default values used for these items are implementation-specific.
If these properties do not have values set, or if other Kerberos configuration information is
needed, an attempt is made to find the required information in a [Link] file. The algorithm
to locate the [Link] file is the following:
• If the system property [Link] is set, its value is assumed to specify the
path and file name.
• If that system property value is not set, then the configuration file is looked for in the
directory
– <java-home>\conf\security (Windows)
– <java-home>/conf/security (Solaris, Linux, and macOS)
Here <java-home> refers to the directory where the JDK is installed.
• If the file is still not found, then an attempt is made to locate it as follows:
– /etc/krb5/[Link] (Solaris)
– C:\Windows\[Link] (Windows)
– /etc/[Link] (Linux)
– ~/Library/Preferences/[Link], /Library/Preferences/
[Link], or /etc/[Link] (macOS)
• If the file is still not found, and the configuration information being searched for is not the
default realm and KDC, then implementation-specific defaults are used. If, on the other
hand, the configuration information being searched for is the default realm and KDC
because they weren't specified in system properties, and the [Link] file is not found
either, then an exception is thrown.
• On Windows, if a [Link] file cannot be found or it does not contain settings for the
default realm and its KDC, then the environment variables USERDNSDOMAIN and
LOGONSERVER are used as the default realm and its KDC.
lowercased DNS hostname when creating host-based principal names in the KDC: host/
[Link].
Cross-Realm Authentication
In cross-realm authentication, a principal in one realm can authenticate to principals in another
realm.
In Kerberos, cross-realm authentication is implemented by sharing an encryption key between
two realms. The KDCs in two different realms share a special cross-realm secret; this secret is
used to prove identity when crossing the boundary between realms.
The key that is shared is the Ticket Granting Service principal's key. Here's a typical Ticket
Granting Service principal for a single realm:
ktbtgt/[Link]@[Link]
In cross realm authentication, two principals are created on each participating realm. For two
realms, [Link] and [Link], these principals would be:
krbtgt/[Link]@[Link]
krbtgt/[Link]@[Link]
These principals, known as remote Ticket Granting Server principals, must be created on both
realms.
For a Windows KDC, the krbtgt account is created automatically when a Windows domain is
created. This account cannot be deleted and renamed.
Troubleshooting
The following are some problems that may occur when attempting a login, and suggestions for
solving them.
• Configurable Kerberos Settings: The Kerberos Key Distribution Center (KDC) name and
realm settings are provided in the Kerberos configuration file or via the system properties
[Link] and [Link]. A boolean option
refreshKrb5Config can be specified in the entry for Krb5LoginModule in the JAAS
configuration file. If this option is set to true, then the configuration values will be refreshed
before the login method of the Krb5LoginModule is called.
Note
When switching Kerberos configurations, it is REQUIRED that refreshKrb5Config
should be set to true. Failure to set this value can lead to unexpected results.
• [Link] at
[Link]
Cause: There was a problem processing the JAAS login configuration file, possibly due to
a syntax error in the file.
Solution: Check the configuration file carefully for errors. See Appendix B: JAAS Login
Configuration File for information about the syntax required in the login configuration file.
[libdefaults]
default_tkt_enctypes = des-cbc-md5 des-cbc-crc des3-cbc-sha1
default_tgs_enctypes = des-cbc-md5 des-cbc-crc des3-cbc-sha1
permitted_enctypes = des-cbc-md5 des-cbc-crc des3-cbc-sha1
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
Value Name: allowtgtsessionkey
Value Type: REG_DWORD
Value: 0x01 ( default is 0 )
By default, the value is 0; setting it to "0x01" allows a session key to be included in the
TGT.
• KDC reply did not match expectations
Cause: The KDC sent a response that cannot be understood by the client.
Solution: Verify that you have set correctly all the [Link] file configuration parameters
and consult your KDC vendor's guide.
Note
A debugging mode can be enabled by setting the system property
[Link] to "true". This setting allows you to follow the
program's execution of the Kerberos V5 protocol.
import [Link].*;
import [Link].*;
import [Link];
import [Link];
/**
* A sample server application that uses JGSS to do mutual authentication
* with a client using Kerberos as the underlying mechanism. It then
* exchanges data securely with the client.
*
* Every message exchanged with the client includes a 4-byte application-
* level header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
* 3. server sends a mic token to the client for the application
* message that was contained in the wrap token.
*/
if ([Link] != 1) {
[Link]("Usage: java <options> Login SampleServer
<localPort>");
[Link](-1);
}
while (true) {
/*
* Create a GSSContext to receive the incoming request
* from the client. Use null for the server credentials
* passed in. This tells the underlying mechanism
* to use whatever credentials it has available that
* can be used to accept this connection.
*/
GSSContext context = [Link]((GSSCredential)null);
while (![Link]()) {
/*
* Create a MessageProp which unwrap will use to return
* information such as the Quality-of-Protection that was
* applied to the wrapped token, whether or not it was
* encrypted, etc. Since the initial MessageProp values
* are ignored, just set them to the defaults of 0 and false.
*/
MessageProp prop = new MessageProp(0, false);
/*
* Read the token. This uses the same token byte array
* as that used during context establishment.
*/
token = new byte[[Link]()];
[Link]("Will read token of size "
+ [Link]);
[Link](token);
/*
* Now generate a MIC and send it to the client. This is
* just for illustration purposes. The integrity of the
* incoming wrapped message is guaranteed irrespective of
* the confidentiality (encryption) that was used.
*/
/*
* First reset the QOP of the MessageProp to 0
* to ensure the default Quality-of-Protection
* is applied.
*/
[Link](0);
+ [Link]);
[Link]([Link]);
[Link](token);
[Link]();
[Link]
/**
* Login Configuration for JAAS.
*/
[Link] {
[Link].Krb5LoginModule required;
};
[Link] {
[Link].Krb5LoginModule required storeKey=true;
};
[Link]
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
/**
* A sample client application that uses JGSS to do mutual authentication
* with a server using Kerberos as the underlying mechanism. It then
* exchanges data securely with the server.
*
* Every message sent to the server includes a 4-byte application-level
* header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
* 3. server sends a MIC token to the client for the application
* message that was contained in the wrap token.
*/
if ([Link] < 3) {
[Link]("Usage: java <options> Login SampleClient "
+ " <server> <hostName> <port>");
[Link](-1);
}
/*
* This Oid is used to represent the Kerberos version 5 GSS-API
* mechanism. It is defined in RFC 1964. We will use this Oid
* whenever we need to indicate to the GSS-API that it must
* use Kerberos for some purpose.
*/
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
/*
* Create a GSSName out of the server's name. The null
* indicates that this application does not wish to make
* any claims about the syntax of this name and that the
* underlying mechanism should try to parse it as per whatever
* default syntax it chooses.
*/
GSSName serverName = [Link](server, null);
/*
* Create a GSSContext for mutual authentication with the
* server.
* - serverName is the GSSName that represents the server.
* - krb5Oid is the Oid that represents the mechanism to
* use. The client chooses the mechanism to use.
* - null is passed in for client credentials
* - DEFAULT_LIFETIME lets the mechanism decide how long the
* context can remain valid.
* Note: Passing in null for the credentials asks GSS-API to
* use the default credentials. This means that the mechanism
* will look among the credentials stored in the current Subject
while (![Link]()) {
/*
* If mutual authentication did not take place, then only the
* client was authenticated to the server. Otherwise, both
* client and server were authenticated to each other.
*/
if ([Link]())
[Link]("Mutual authentication took place!");
/*
* The first MessageProp argument is 0 to request
* the default Quality-of-Protection.
* The second argument is true to request
* privacy (encryption of the message).
*/
MessageProp prop = new MessageProp(0, true);
/*
* Encrypt the data and send it across. Integrity protection
* is always applied, irrespective of confidentiality
* (i.e., encryption).
* You can use the same token (byte array) as that used when
* establishing the context.
*/
/*
* Now we will allow the server to decrypt the message,
* calculate a MIC on the decrypted message and send it back
* to us for verification. This is unnecessary, but done here
* for illustration.
*/
[Link]("Exiting...");
[Link]();
[Link]();
}
}
[Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
/**
try {
// attempt authentication
[Link]();
[Link]("Authentication failed:");
[Link](" " + [Link]());
[Link](-1);
[Link]("Authentication succeeded!");
}
}
[Link]
JaasSample {
[Link].Krb5LoginModule required;
};
[Link]
/** Java Access Control Policy for the JaasAcn Application **/
permission [Link]
"[Link]";
};
[Link]
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
/**
* This JaasAzn application attempts to authenticate a user
* and reports whether or not the authentication was successful.
* If successful, it then sets up subsequent execution of
* code in the run method of the SampleAction class such that
* access control checks for security-sensitive operations will be
* based on the user running the code.
*/
public class JaasAzn {
try {
// attempt authentication
[Link]();
[Link]("Authentication failed:");
[Link](" " + [Link]());
[Link](-1);
[Link]("Authentication succeeded!");
}
}
[Link]
import [Link];
import [Link];
/**
* This is a sample PrivilegedAction implementation, designed to be
* used with the JaasAzn class.
*/
public class SampleAction implements PrivilegedAction {
/**
* This sample PrivilegedAction performs the following operations:
* <ul>
* <li> Access the System property <i>[Link]</i>
* <li> Access the System property <i>[Link]</i>
* <li> Access the file <i>[Link]</i>
* </ul>
*
* @return <code>null</code> in all cases.
*
* @exception SecurityException if the caller does not have permission
* to perform any of these operations.
*/
public Object run() {
[Link]("\nYour [Link] property value is: "
+[Link]("[Link]"));
}
}
[Link]
/** Java Access Control Policy for the JaasAzn Application **/
permission [Link]
"[Link]";
permission [Link] "doAsPrivileged";
};
[Link]
import [Link].*;
import [Link].*;
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
/**
* <p> This class authenticates a <code>Subject</code> and then
* executes a specified application as that <code>Subject</code>.
* To use this class, the java interpreter would typically be invoked as:
*
* <pre>
* % java -[Link] \
* Login \
* <applicationclass> <applicationClass_args>
* </pre>
*
* <p> <i>applicationClass</i> represents the application to be executed
* as the authenticated <code>Subject</code>,
* and <i>applicationClass_args</i> are passed as arguments to
* <i>applicationClass</i>.
*
* <p> To perform the authentication, <code>Login</code> uses a
* <code>LoginContext</code>. A <code>LoginContext</code> relies on a
* <code>Configuration</code> to determine the modules that should be used
* to perform the actual authentication. The location of the Configuration
* is dependent upon each Configuration implementation.
* The default Configuration implementation
* (<code>[Link]</code>)
* allows the Configuration location to be specified (among other ways)
* via the <code>[Link]</code> system property.
* Therefore, the <code>Login</code> class can also be invoked as:
*
* <pre>
* % java -[Link] \
* -[Link]=<configuration_url> \
* Login \
* <your_application_class> <your_application_class_args>
* </pre>
*/
/**
* <p> Instantate a <code>LoginContext</code> using the
* provided application classname as the index for the login
* <code>Configuration</code>. Authenticate the <code>Subject</code>
* (three retries are allowed) and invoke
* <code>[Link]</code>
* with the authenticated <code>Subject</code> and a
* <code>PrivilegedExceptionAction</code>.
* The <code>PrivilegedExceptionAction</code>
* loads the provided application class, and then invokes
* its public static <code>main</code> method, passing it
* the application arguments.
*
* <p>
*
* @param args the arguments for <code>Login</code>. The first
* argument must be the class name of the application to be
* invoked once authentication has completed, and the
* subsequent arguments are the arguments to be passed
* to that application's public static <code>main</code> method.
*/
public static void main(String[] args) {
LoginContext lc = null;
try {
lc = new LoginContext(args[0], new TextCallbackHandler());
// attempt authentication
[Link]();
[Link]("Authentication Failed");
try {
[Link]().sleep(3000);
} catch (Exception e) {
// ignore
}
} catch (Exception e) {
[Link](0);
}
}
String[] origArgs;
try {
// get the application class's main method
Class c = [Link](origArgs[0], true, cl);
Class[] PARAMS = { [Link]() };
[Link] mainMethod = [Link]("main", PARAMS);
// successful completion
return null;
}
}
[Link]
import [Link];
/**
* This sample class performs the following operations:
* <ul>
* <li> Access the System property <i>[Link]</i>
* <li> Access the System property <i>[Link]</i>
* <li> Access the file <i>[Link]</i>
* </ul>
*
* @exception SecurityException if the caller does not have permission
* to perform any of these operations.
*/
public static void main (String[] args) throws SecurityException {
[Link]
Sample {
[Link].Krb5LoginModule required;
};
[Link]
[Link]
/**
* Login Configuration for JAAS.
*/
SampleClient {
[Link].Krb5LoginModule required;
};
SampleServer {
[Link].Krb5LoginModule required storeKey=true
principal="service_principal@your_realm";
};
[Link]
permission [Link]
"krbtgt/your_realm@your_realm",
"initiate";
permission [Link]
"service_principal@your_realm",
"initiate";
};
[Link]
permission [Link]
"service_principal@your_realm", "accept";
};
[Link]
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
/**
* A sample server application that uses JGSS to do mutual authentication
* with a client using Kerberos as the underlying mechanism. It then
* exchanges data securely with the client.
*
* Every message exchanged with the client includes a 4-byte application-
* level header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
* 3. server sends a mic token to the client for the application
* message that was contained in the wrap token.
*/
if ([Link] != 1) {
[Link]("Usage: java <options> Login SampleServer
<localPort>");
[Link](-1);
}
while (true) {
new DataOutputStream([Link]());
/*
* Create a GSSContext to receive the incoming request
* from the client. Use null for the server credentials
* passed in. This tells the underlying mechanism
* to use whatever credentials it has available that
* can be used to accept this connection.
*/
GSSContext context = [Link]((GSSCredential)null);
while (![Link]()) {
/*
* Create a MessageProp which unwrap will use to return
* information such as the Quality-of-Protection that was
* applied to the wrapped token, whether or not it was
/*
* Read the token. This uses the same token byte array
* as that used during context establishment.
*/
token = new byte[[Link]()];
[Link]("Will read token of size "
+ [Link]);
[Link](token);
/*
* Now generate a MIC and send it to the client. This is
* just for illustration purposes. The integrity of the
* incoming wrapped message is guaranteed irrespective of
* the confidentiality (encryption) that was used.
*/
/*
* First reset the QOP of the MessageProp to 0
* to ensure the default Quality-of-Protection
* is applied.
*/
[Link](0);
/*
* Impersonate client
*/
[Link]("Impersonating client.");
/*
* Extract the KerberosPrincipal from the client GSSName and
populate
* it in the principal set of a new Subject. Pass in a null for
* credentials. If we were to pass in the delegated GSSCredential
/*
* Construct an action that will read a file meant only for the
* client
*/
PrivilegedAction readFile =
new ReadFileAction([Link]());
/*
* Invoke the action via a doAsPrivileged. This allows the
* action to be executed as the client subject, and it also runs
* that code as privileged. This means that any permission
checking
* that happens beyond this point applies only to the code being
* run as the client.
*/
[Link](client, readFile, null);
/*
* Clean up
*/
[Link]
import [Link];
import [Link].*;
/**
* This class implements the PrivilegedAction interface to demonstrate the
* reading of a file that belongs to the client. This code will be
* executed by the server while impersonating the client principal.
*/
public class ReadFileAction implements PrivilegedAction {
/**
* Contructs a ReadFileAction instance.
*
* @param kerberosPrincipalName the name of the Kerberos principal
* who owns the file that will be read. The filename is constructed
* from the name of the principal.
*/
public ReadFileAction(String kerberosPrincipalName) {
/*
* Separate the realm component from the name and use the rest of
* it for constructing the filename. If the principal name is
* "joe@REALM" then the file that will be read is
* "data/joe_info.txt". The path separator "/" might be "\" in the
* case of Windows.
*/
int realmSeparatorPos = [Link]('@');
fileName = "data" + [Link]
+ [Link](0, realmSeparatorPos)
+ "_info.txt";
}
/**
* Does the actual reading of the file. It displays the text contained
* in the file.
*/
public Object run() {
[Link]("===============================================");
[Link]("Reading file: " + fileName);
try {
BufferedReader reader = new BufferedReader(new
FileReader(fileName));
String str = [Link]();
while (str != null) {
[Link](str);
str = [Link]();
}
} catch (IOException e) {
[Link](e);
}
[Link]("===============================================");
return null;
}
}
[Link]
permission [Link]
"service_principal@your_realm", "accept";
permission [Link]
"data/your_user_name_info.txt", "read";
};
[Link]
/**
* Login Configuration for JAAS.
*/
SampleClient {
[Link].Krb5LoginModule required;
};
SampleServerImp {
[Link].Krb5LoginModule required storeKey=true
principal="service_principal@your_realm";
};
Related Documentation
• API specifications
– [Link] package
– [Link] package
– [Link] package
– [Link] package
– [Link] package
• User guides and tutorials
– Java Authentication and Authorization Service (JAAS) Reference Guide
– Java Security Tutorial
• Other Java Security Documentation
– Default Policy Implementation and Policy File Syntax
– Permissions in the JDK
– Single Sign-on Using Kerberos in Java
– Java SE Platform Security Architecture
• Reference document
– Generic Security Service API Version 2: Java Bindings Update
then the Java GSS-API mandates that the credentials be obtained from the private or public
credential sets of the current Subject and that the Java GSS-API call must fail if the desired
credential cannot be found. Thus, Java platform applications that execute the Java GSS-API
calls inside a [Link]/doAsPrivileged(...) call should either populate the Subject's
credential sets with the appropriate Java GSSCredential objects that encapsulate the native
credentials or explicitly set the system property [Link]
to false so that the Java GSS-API can obtain credentials from other locations, for example,
from native credential caches, in addition to the Subject's credential sets.
When delegated to establish a GSS-API security context on behalf of others, Java applications
can either specify the delegated credential, as returned by [Link](),
explicitly in Java GSS-API calls, or create a Subject object with this delegated credential and
execute the Java GSS-API calls inside the [Link]/doAsPrivileged(...) calls.
Once the native GSS-API is enabled, Java platform applications that indirectly call Java GSS-
API through mechanisms or protocols such as Simple Authentication and Security Layer
(SASL) (see Java SASL API Programming and Deployment Guide) will also use user's native
settings and credentials.
Here is some sample code that helps demonstrate how to use Java GSS-API to establish
GSS-API security contexts and securely exchange data between three parties: SampleClient
contacts FooServer, which in turn contacts FooServer2 on behalf of SampleClient. Note:
• The sample code should be invoked with native GSS-API enabled. The Principal names
host@[Link] and host@[Link] are placeholders and should be
replaced with actual principal names in your Kerberos database.
• When a security manager is installed, some Java GSS-API calls require that permissions
be granted. Check the Java documentation of the following classes for more details:
– [Link]
– [Link]
• To simplify the example, token exchanges between peers are represented by two pseudo-
methods: SEND_TOKEN(byte[]) and READ_TOKEN(). Their actual implementation are
application-specific and thus not shown here.
• To reduce code duplication, context establishment code is referred by a pseudo-method,
ESTABLISH_CONTEXT(GSSContext), in the code segments for SampleClient, FooServer,
and FooServer2.
The following is the implementation for ESTABLISH_CONTEXT(GSSContext) using Java GSS-API.
/**
* ESTABLISH_CONTEXT(GSSContext ctxt): establishes a context
* with data confidentiality and mutual authentication.
*/
[Link](true);
[Link](true);
if ([Link]()) {
while (![Link]()) {
// Note: initSecContext(...) always ignores the arguments
// for the first call because there is no incoming token.
outToken = [Link](inToken, 0, [Link]);
[Link](inToken, 0, [Link]);
Following are the code segments for SampleClient, FooServer, and FooServer2:
SampleClient: It contacts FooServer and delegates the server to act on its behalf. If all goes
well, it should get back a personalized hello message produced by FooServer2.
GSSManager gssMgr = [Link]();
GSSName serverName = [Link](
"host@[Link]", GSSName.NT_HOSTBASED_SERVICE);
GSSContext context = [Link](
serverName, null /* default mechanism, which is Kerberos*/,
null /* default initiator cred */,
GSSContext.DEFAULT_LIFETIME);
[Link](true);
ESTABLISH_CONTEXT(context);
ESTABLISH_ACC_CONTEXT(acontext);
GSSContext.DEFAULT_LIFETIME);
ESTABLISH_CONTEXT(icontext);
FooServer2: It always replies with a hello message personalized to the name of the initiator of
the established context.
GSSManager gssMgr = [Link]();
GSSName myName = [Link](
"host@[Link]", GSSName.NT_HOSTBASED_SERVICE);
GSSCredential myCred = [Link](
myName, GSSCredential.INDEFINITE_LIFETIME,
(Oid[]) null /* default set of mechanisms */,
GSSCredential.ACCEPT_ONLY);
GSSContext context = [Link](myCred);
ESTABLISH_CONTEXT(context);
SEND_TOKEN(token); // to "FooServer"
[Link]();
Abstract
A significant enhancement to the Java SE security architecture is the capability to achieve
single sign-on using Kerberos Version 5. A single sign-on solution lets users authenticate
themselves just once to access information on any of several systems. This is done using
JAAS for authentication and authorization and Java GSS-API to establish a secure context for
communication with a peer application. Our focus is on Kerberos V5 as the underlying security
mechanism for single sign-on, although other security mechanisms may be added in the future.
Introduction
With the increasing use of distributed systems users need to access resources that are often
remote. Traditionally users have had to sign-on to multiple systems, each of which may involve
different user names and authentication techniques. In contrast, with single sign-on, the user
needs to authenticate only once and the authenticated identity is securely carried across the
network to access resources on behalf of the user.
In this paper we discuss how to use single sign-on based on the Kerberos V5 protocol. We use
the Java Authentication and Authorization Service (JAAS) to authenticate a principal to
Kerberos and obtain credentials that prove its identity. We show how Oracle's implementation
of a Kerberos login module can be made to read credentials from an existing cache on
platforms that contain native Kerberos support. We then use the Java Generic Security Service
API (Java GSS-API) to authenticate to a remote peer using the previously obtained Kerberos
credentials. We also show how to delegate Kerberos credentials for single sign-on in a multi-
tier environment.
Kerberos V5
Kerberos V5 is a trusted third party network authentication protocol designed to provide strong
authentication using secret key cryptography. When using Kerberos V5, the user's password is
never sent across the network, not even in encrypted form, except during Kerberos V5
administration. Kerberos was developed in the mid-1980's as part of MIT's Project Athena. A
full description of the Kerberos V5 protocol is beyond the scope of this paper. For more
information on the Kerberos V5 protocol please refer to [1] and [2].
Kerberos V5 is a mature protocol and has been widely deployed. A free reference
implementation in C is available from MIT. For these reasons we have selected Kerberos V5 as
the underlying technology for single sign-on in Java SE.
The JAAS authorization component supplements the existing Java security framework by
providing the means to restrict the executing Java code from performing sensitive tasks,
depending on its codesource and depending on who is executing the code.
Subject
JAAS uses the term Subject to refer to any entity that is the source of a request to access
resources. A Subject may be a user or a service. Since an entity may have many names or
principals JAAS uses Subject as an extra layer of abstraction that handles multiple names per
entity. Thus a Subject is comprised of a set of principals. There are no restrictions on principal
names.
A Subject is only populated with authenticated principals. Authentication typically involves the
user providing proof of identity, such as a password.
A Subject may also have security related attributes, which are referred to as credentials. The
credentials can be public or private. Sensitive credentials such as private cryptographic keys
are stored in the private credentials set of the Subject.
The Subject class has methods to retrieve the principals, public credentials and private
credentials associated with it.
Please note that different permissions may be required for operations on these classes. For
example AuthPermission("modifyPrincipals") may be required to modify the principal
set of the Subject. Similar permissions are required to modify the public credentials, private
credentials and to get the current Subject.
Warning
The Security Manager and APIs related to it have been deprecated and are subject to
removal in a future release. There is no replacement for the Security Manager. See
JEP 411 for discussion and alternatives.
JAAS provides two methods, doAs and doAsPrivileged, that can be used to associate an
authenticated Subject with the AccessControlContext dynamically.
The doAs method associates the Subject with the current thread's access control context and
subsequent access control checks are made on the basis of the code being executed and the
Subject executing it.
Both forms of the doAs method first associate the specified subject with the current Thread's
AccessControlContext, and then execute the action. This achieves the effect of having the
action run as the Subject. The first method can throw runtime exceptions but normal execution
has it returning an Object from the run() method of its action argument. The second method
behaves similarly except that it can throw a checked PrivilegedActionException from its
run() method. An AuthPermission("doAs") is required to call the doAs methods.
The doAsPrivileged method behaves exactly as doAs, except that it allows the caller to
specify an access control context. Thus it effectively throws away the current
AccessControlContext and authorization decisions will be based on the
AccessControlContext passed in.
Since the AccessControlContext is set on a per thread basis, different threads within the
JVM can assume different identities. The Subject associated with a specific
AccessControlContext can be retrieved by using the following method:
LoginContext
The LoginContext class provides the basic methods used to authenticate Subjects. It also
allows an application to be independent of the underlying authentication technologies. The
LoginContext consults a configuration that determines the authentication services or
LoginModules configured for a particular application. If the application does not have a
specific entry, it defaults to the entry identified as "other".
To support the stackable nature of LoginModules, LoginContext performs authentication
in two phases. In the first phase or login phase, it invokes each configured LoginModule to
attempt the authentication. If all the necessary LoginModules succeed, then LoginContext
enters the second phase where it invokes each LoginModule again to formally commit the
authentication process. During this phase the Subject is populated with the authenticated
principals and their credentials. If either of the phase fails, then the LoginContext invokes
each configured module to abort the entire authentication attempt. Each LoginModule then
cleans up any relevant state associated with the authentication attempt.
LoginContext has four constructors that can be used to instantiate it. All of them require the
configuration entry name to be passed. In addition the Subject and/or a CallbackHandler
can also be passed to the constructors.
Callbacks
The login modules invoked by JAAS must be able to garner information from the caller for
authentication. For example the Kerberos login module may require users to enter their
Kerberos password for authentication.
The LoginContext allows the application to specify a callback handler that the underlying
login modules use to interact with users. There are two callback handlers - one based on the
command line and another based on a GUI.
LoginModules
Oracle provides an implementation of the UnixLoginModule, NTLoginModule,
JNDILoginModule, KeyStoreLoginModule and Krb5LoginModule.
SampleClient {
[Link].Krb5LoginModule required useTicketCache=true
};
The following is a sample login configuration entry for a server application. With this
configuration, the secret key from the keytab is used to authenticate the principal nfs/
[Link] and both the TGT obtained from the Kerberos KDC and the secret key are
stored in the Subject's private credentials set. The stored key may be used later to validate a
service ticket sent by a client (See the section on Java GSS-API.)
Example 7-2 Sample Server Configuration Entry
SampleServer {
[Link].Krb5LoginModule
required useKeyTab=true storeKey=true principal="nfs/[Link]"
};
In the following client code example, the configuration entry SampleClient will be used by the
LoginContext. The TextCallbackHandler class will be used to prompt the user for the
Kerberos password. Once the user has logged in, the Subject will be populated with the
Kerberos Principal name and the TGT. Thereafter the user can execute code using
[Link] passing in the Subject obtained from the LoginContext.
LoginContext lc = null;
try {
lc = new LoginContext("SampleClient", new TextCallbackHandler());
// attempt authentication
[Link]();
} catch (LoginException le) {
...
}
ClientAction could be an action that is allowed only for authenticated Kerberos client
Principals with a specific value.
The following shows server side sample code. It is similar to Example 7-3 except for the
application entry name and the PrivilegedAction.
LoginContext lc = null;
try {
lc = new LoginContext("SampleServer", new TextCallbackHandler());
// attempt authentication
[Link]();
} catch (LoginException le) {
...
}
Kerberos Classes
To enable other vendors to provide their own Kerberos login module implementation that can
be used with Java GSS-API, three standard Kerberos classes have been introduced in the
[Link] package. These are KerberosPrincipal for
Kerberos principals, KerberosKey for the long-term Kerberos secret key and
KerberosTicket for Kerberos tickets. All implementations of the Kerberos login module must
use these classes to store principals, keys and tickets in the Subject.
Authorization
Upon successful authentication of a Subject, access controls can be enforced based upon the
principals associated with the authenticated Subject. The JAAS principal based access
controls augment the CodeSource access controls of Java SE. Permissions granted to a
Subject are configured in Policy, which is an abstract class for representing the system wide
access control policy. Oracle provides a file based implementation of the Policy class. The
Policy class is provider based so that others can provide their own policy implementation.
Mechanisms are identified by means of unique object identifier's (OID's) that are registered
with the IANA. For instance, the Kerberos V5 mechanism is identified by the OID {iso(1)
member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) krb5(2)}
Another important feature of the API is that it is token based. i.e., Calls to the API generate
opaque octets that the application must transport to its peer. This enables the API to be
transport independent.
Java GSS-API
The Java API for the Generic Security Service was also defined at the IETF and is
documented in RFC 2853 [10]. Oracle is pursuing the standardization of this API under the
Java Community Process (JCP) [11] and plans to deliver a reference implementation with
Merlin. Because the JCP is merely endorsing this externally defined API, the IETF assigned
package namespace [Link] will be retained in Merlin.
Oracle's implementation of Java GSS-API, will initially ship with support for the Kerberos V5
mechanism only. Kerberos V5 mechanism support is mandatory for all Java GSS-API
implementations in Java SE, although they are free to support additional mechanisms. In a
future release, a Service Provider Interface (SPI) will be added so that new mechanisms can
be configured statically or even at runtime. Even now the reference implementation in Merlin
will be modular and support a private provider SPI that will be converted to public when
standardized.
The Java GSS-API framework itself is quite thin, and all security related functionality is
delegated to components obtained from the underlying mechanisms. The GSSManager class
is aware of all mechanism providers installed and is responsible for invoking them to obtain
these components.
The implementation of the default GSSManager that will ship with Java SE is obtained as
follows:
The GSSManager can be used to configure new providers and to list all mechanisms already
present. The GSSManager also serves as a factory class for three important interfaces:
GSSName, GSSCredential, and GSSContext. The following sections describe these
interfaces with the methods to instantiate their implementations. For a complete API
specification, readers are referred to [9] and [11].
Most calls to Java GSS-API throw a GSSException that encapsulate problems that occur
both within the GSS-API framework, and within the mechanism providers.
For example:
This call returns a GSSName that represents the user principal duke at a mechanism
independent level. Internally, it is assumed that each supported mechanism will map the
generic representation of the user to a more mechanism specific form. For instance a Kerberos
V5 mechanism provider might map this name to duke@[Link] where [Link] is the
local Kerberos realm. Similarly, a public key based mechanism provider might map this name
to an X.509 Distinguished Name.
If we were referring to a principal that was not a user, but some sort of service, we would
indicate that to the Java GSS-API call so that the mechanism knows to interpret it differently.
Example:
The Kerberos V5 mechanism would map this name to the Kerberos specific form nfs/
[Link]@[Link] where [Link] is the realm of the principal. This principal
represents the service nfs running on the host machine [Link].
Oracle's implementation of the GSSName interface is a container class. The container class lazily
asks the individual providers to perform their mapping when their mechanism is used and then
stores each mapped element in a set of principals. In this respect an implementation of
GSSName is similar to the principal set stored in a Subject. It may even contain the same
elements that are in a Subject's principal set, but its use is restricted to the context of Java
GSS-API.
The name element stored by the Oracle Kerberos V5 provider is an instance of a subclass of
[Link].
GSSCredential clientCreds =
[Link](clientName,
8*3600,
desiredMechs,
GSSCredential.INITIATE_ONLY);
The GSSManager invokes the providers of the mechanisms listed in the desiredMechs for
credentials that belong to the GSSName clientName. Additionally, it imposes the restriction
that the credential must be the kind that can initiate outbound requests (i.e., a client credential),
and requests a lifetime of 8 hours for it. The returned object contains elements from a subset of
desiredMechs that had some credential available to satisfy this criteria. The element stored
by the Kerberos V5 mechanism is an instance of a subclass of
[Link] containing a TGT that belongs to
the user.
Credential acquisition on the server side occurs as follows:
GSSCredential serverCreds =
[Link](serverName,
GSSCredential.INDEFINITE_LIFETIME,
desiredMechs,
GSSCredential.ACCEPT_ONLY);
The behavior is similar to the client case, except that the kind of credential requested is one
that can accept incoming requests (i.e., a server credential). Moreover, servers are typically
long lived and like to request a longer lifetime for the credentials such as the
INDEFINITE_LIFETIME shown here. The Kerberos V5 mechanism element stored is an
instance of a subclass of [Link] containing the
secret key of the server.
This step can be an expensive one, and applications generally acquire a reference at
initialization time to all the credentials they expect to use during their lifetime.
int lifetime)
throws GSSException
This returns an initialized security context that is aware of the peer that it must communicate
with and the mechanism that it must use to do so. The client's credentials are necessary to
authenticate to the peer.
On the server side the GSSContext is obtained as follows:
This returns an initialized security context on the acceptor's side. At this point it does not know
the name of the peer (client) that will send a context establishment request or even the
underlying mechanism that will be used. However, if the incoming request is not for service
principal represented by the credentials serverCreds, or the underlying mechanism
requested by the client side does not have a credential element in serverCreds, then the
request will fail.
Before the GSSContext can be used for its security services it has to be established with an
exchange of tokens between the two peers. Each call to the context establishment methods
will generate an opaque token that the application must somehow send to its peer using a
communication channel of its choice.
The client uses the following API call to establish the context:
throws GSSException
throws GSSException
These two methods are complementary and the input accepted by one is the output generated
by the other. The first token is generated when the client calls initSecContext for the first
time. The arguments to this method are ignored during that call. The last token generated
depends on the particulars of the security mechanism being used and the properties of the
context being established.
The number of round trips of GSS-API tokens required to authenticate the peers varies from
mechanism to mechanism and also varies with characteristics such as whether mutual
authentication or one-way authentication is desired. Thus each side of the application must
continue to call the context establishment methods in a loop until the process is complete.
In the case of the Kerberos V5 mechanism, there is no more than one round trip of tokens
during context establishment. The client first sends a token generated by its
initSecContext() containing the Kerberos AP-REQ message [2]. In order to generate the
AP-REQ message, the Kerberos provider obtains a service ticket for the target server using
the client's TGT. The service ticket is encrypted with the server's long-term secret key and is
encapsulated as part of the AP-REQ message. After the server receives this token, it is passed
to the acceptSecContext() method which decrypts the service ticket and authenticates the
client. If mutual authentication was not requested, both the client and server side contexts
would be established, and the server side acceptSecContext() would generate no output.
while (!established) {
outToken =
[Link](inToken, 0, [Link]);
if (![Link]()) {
inToken = readToken();
else
established = true;
}
} catch (GSSException e) {
....
}
...
...
}
}
The corresponding section of code on the server side running the ServerAction class from the
sample server code in the section The Kerberos Login Module:
Example 7-6 Sample Server Using Java GSS-API
sendToken(outToken);
}
} catch (GSSException e) {
...
}
...
...
}
}
Message Protection
Once the security context is established, it can be used for message protection. Java GSS-API
provides both message integrity and message confidentiality. The two calls that enable this are
as follows:
and
The wrap method is used to encapsulate a cleartext message in a token such that it is integrity
protected. Optionally, the message can also be encrypted by requesting this through a
MessageProp object. The wrap method returns an opaque token that the caller sends to its
peer. The original cleartext is returned by the peer's unwrap method when the token is passed
to it. The MessageProp object on the unwrap side returns information about whether the
message was simply integrity protected or whether it was encrypted as well. It also contains
sequencing and duplicate token warnings.
Credential Delegation
Java GSS-API allows the client to securely delegate its credentials to the server, such that the
server can initiate other security contexts on behalf of the client. This feature is useful for single
sign-on in a multi-tier environment. Figure 7-2 illustrates this.
The client requests credential delegation prior to making the first call to initSecContext():
cannot occur. However, because MS-SFU defines the Service for User (S4U2self) extension
so that the front end can access the back end on behalf of the client without presenting the
client's Kerberos credentials, MS-SFU could provide authentication in this situation. Figure 7-3
illustrates this.
In addition, there are potential security gaps in the standard Kerberos 5 delegation mechanism
(which Microsoft calls open delegation). In this mechanism, once the service account has the
client's delegated credentials, it has access to any service. Thus, great care is needed with
open delegation.
In contrast, with MS-SFU delegation (implemented in S4U2proxy), the administrator can
precisely control the services to which a particular service can access on behalf a client.
Figure 7-4 illustrates this.
Note
To delegate credentials as specified in the RFCs in this document, you must use
traditional delegation. With constrained delegation, the client is unable to determine if
its own credentials can be delegated because this is determined by the KDC.
two sub-sections will focus on how Java GSS-API mechanisms obtain these credentials. The
mechanisms do not themselves perform a user login. Instead, the login is performed prior to
using Java GSS-API and the credentials are assumed to be stored in some cache that the
mechanism provider is aware of. The [Link]() method merely
obtains references to those credentials and returns them in a GSS-centric container, the
GSSCredential.
In Java SE, we impose the restriction that the credentials cache that Java GSS-API
mechanism providers use to obtain these elements must exclusively be the public and private
credential sets in the Subject that is on the current access control context.
This model has the advantage that credential management is simple and predictable from the
application's point of view. An application, given the right permissions, can purge the
credentials in the Subject or renew them using standard Java API's. If it purged the credentials,
it would be sure that the Java GSS-API mechanism would fail, or if it renewed a time based
credential it would be sure that the mechanism would succeed.
Here is the sequence of events relevant to credential acquisition when the Kerberos V5
mechanism is used by the client application in Example 7-3 and Example 7-5:
1. The application invokes a JAAS login, which in turn invokes the configured
Krb5LoginModule
2. Krb5LoginModule obtains a TGT (an instance of KerberosTicket) for the user either
from the KDC or from an existing ticket cache, and stores this TGT in the private
credentials set of a Subject.
Note
Krb5LoginModule can locate an initial TGT inside a credential cache (either an
MIT krb5-style Kerberos credential cache (ccache) file, or a native service such as
Windows Local Security Authority (LSA)), and create a credential for the principal
that owns the TGT.
In addition, if the credential cache is an MIT krb5 ccache file that contains a
proxy_impersonator configuration key (see Credential Cache File Format), then
Krb5LoginModule will attempt to read an evidence ticket from the same ccache
file and create a delegated credential for the principal that owns this evidence
ticket instead. This delegated credential can be used in constrained delegation.
You can retrieve the owner of the credential by calling the
[Link]() method from the acquired credential or the
getSrcName() method of an established GSSContext object created by this
credential.
If there is no valid Kerberos credential in the current Subject, and this property is true, then the
Kerberos mechanism throws a GSSException. Setting this property to false does not
necessarily mean that the provider has to use a cache other than the current Subject, it only
gives the provider the latitude to do so if it wishes.
The Oracle provider for the Kerberos V5 GSS-API mechanism always obtains credentials from
a Subject. If there are no valid credentials in the current Subject, and this property is set to
false, then the provider attempts to obtain new credentials from a temporary Subject by
invoking a JAAS login itself. It uses the text callback handler for input/output with the user, and
the JAAS configuration entry identified by "other" for the list of modules and options to use.
(Actually, it first tries to use the JAAS configuration entry [Link] for
the client and [Link] for the server and falls back on the entry for
"other" if these entries are missing. This gives system administrators some additional control
over its behavior.)
The Oracle provider for the Kerberos V5 GSS-API mechanism assumes that one of these
modules will be a Kerberos login module. It is possible to configure the modules listed under
"other" to read a pre-existing cache so that the user is not unexpectedly prompted for a
password in the middle of a Java GSS-API call. The new Subject that is populated by this login
is discarded by the Kerberos GSS-API mechanism just as soon as the required credentials are
retrieved from it.
Security Risks
The convenience of single sign-on also introduces new risks. What happens if a malicious user
gains access to your unattended desktop from where he or she can start applets as you? What
happens if malicious applets sign on as you to services that they are not supposed to?
For the former, we have no solution but to caution you against leaving your workstation
unlocked! For the latter, we have many authorizations checks in place.
To illustrate some details of the permissions model consider an example where your browser
has performed a JAAS login at startup time and associated a Subject with all applets that run
in it.
The Subject is protected from rogue applets by means of the
[Link] class. This permission is checked whenever
code tries to obtain a reference to the Subject associated with any access control context.
Even if an applet were given access to a Subject, it needs a
[Link] to actually read the sensitive
private credentials stored in it.
Other kinds of checks are to be done by Java GSS-API mechanism providers as they read
credentials and establish security contexts on behalf of the credential's owner. In order to
support the Kerberos V5 mechanism, two new permission classes have been added with the
package [Link]:
As new GSS-API mechanisms are standardized for Java SE, more packages will be added
that contain relevant permission classes for providers of those mechanisms.
The Kerberos GSS-API mechanism permission checks take place at the following points in the
program's execution:
Credential Acquisition
The [Link]() method obtains mechanism specific credential
elements from a cache such as the current Subject and stores them in a GSSCredential
container. Allowing applets to acquire GSSCredential freely, even if they cannot use them to
do much, is undesirable. Doing so leaks information about the existence of user and service
principals. Thus, before an application can acquire a GSSCredential with any Kerberos
credential elements in it, a ServicePermission check is made.
On the client side, a successful GSSCredential acquisition implies that a TGT has been
accessed from a cache. Thus the following ServicePermission is checked:
ServicePermission("krbtgt/[Link]@[Link]", "initiate");
ServicePermission("nfs/[Link]@[Link]", "accept");
Here the service principal nfs/[Link] represents the Kerberos service principal and
the action "accept" suggests that the secret key for this service is being requested.
Context Establishment
An applet that has permissions to contact a particular server, say the LDAP server, must not
instead contact a different server such as the FTP server. Of course, the applet might be
restricted from doing so with the help of SocketPermission. However, it is possible to use
ServicePermission to restrict it from authenticating using your identity, even if the network
connection was permitted.
When the Kerberos mechanism provider is about to initiate context establishment it checks the
ServicePermission:
ServicePermission("ftp@[Link]", "initiate");
This check prevents unauthorized code from obtaining and using a Kerberos service ticket for
the principal ftp@[Link].
Providing limited access to specific service principals using this permission is still dangerous.
Downloaded code is allowed to communicate back with the host it originated from. A malicious
applet could send back the initial GSS-API output token that contains a KerberosTicket
encrypted in the target service principal's long-term secret key, thus exposing it to an offline
dictionary attack. For this reason it is not advisable to grant any "initiate"
ServicePermission to code downloaded from untrusted sites.
On the server side, the permission to use the secret key to accept incoming security context
establishment requests is already checked during credential acquisition. Hence, no checks are
made in the context establishment stage.
Credential Delegation
An applet that has permission to establish a security context with a server on your behalf also
has the ability to request that your credentials be delegated to that server. But not all servers
are trusted to the extent that your credentials can be delegated to them. Thus, before a
Kerberos provider obtains a delegated credential to send to the peer, it checks the following
permission:
This permission allows the Kerberos service principal ftp@[Link] to receive a forwarded
TGT (represented by the ticket granting service krbtgt/[Link]@[Link]). The use
of two principal names in this permission allows for finer grained delegation such as proxy
tickets for specific services unlike a carte blanche forwarded TGT. Even though the GSS-API
does not allow for proxy tickets, another API such as JSSE might support this idea at some
point in the future.
Conclusions
In this paper we have presented a framework to enable single sign-on in Java. This requires
sharing of credentials between JAAS which does the initial authentication to obtain credentials,
and Java GSS-API which uses those credentials to communicate securely over the wire. We
have focused on Kerberos V5 as the underlying security mechanism, but JAAS's stackable
architecture and Java GSS-API's multi-mechanism nature allow us to use any number of
different mechanisms simultaneously.
The Kerberos login module for JAAS is capable of reading native caches so that users do not
have to authenticate themselves beyond desktop login on platforms that support Kerberos.
Moreover, the Kerberos V5 mechanism for Java GSS-API allows credentials to be delegated
which enables single sign-on in multi-tier environments.
Finally, a number of permissions checks are shown to prevent the unauthorized use of the
single-sign on features provided by Kerberos.
Acknowledgements
We thank Gary Ellison, Charlie Lai, and Jeff Nisewanger for their contribution at each stage of
the Kerberos single sign-on project. JAAS 1.0 was implemented by Charlie as an optional
package for Kestrel (J2SE 1.3). Gary has been instrumental in designing the permissions
model for the Kerberos Java GSS-API mechanism. We are grateful to Bob Scheifler for his
feedback on integrating JAAS 1.0 into Merlin and to Tim Blackman for the
KeyStoreLoginModule and CallbackHandler implementations. We also thank Bruce Rich, Tony
Nadalin, Thomas Owusu and Yanni Zhang for their comments and suggestions. We thank
Mary Dageforde for the documentation and tutorials. Sriramulu Lakkaraju, Stuart Ke and Shital
Shisode contributed tests for the projects. Maxine Erlund provided management support for the
project.
References
1. Neuman, Clifford and Tso, Theodore (1994). Kerberos: An Authentication Service for
Computer Networks, IEEE Communications, volume 39 pages 33-38
2. [Link] and [Link]. The Kerberos Network Authentication Service (V5) Internet
Engineering Task Force, September 1993 Request for Comments 1510
3. V. Samar and C. Lai. Making Login Services Independent from Authentication
Technologies. In Proceedings of the SunSoft Developer's Conference, March 1996.
4. X/Open Single Sign-On Service (XSSO) - Pluggable Authentication. Preliminary
Specification P702, The Open Group, June 1997. [Link]
5. L. Gauteron and P. Girard. A Smart Card Login Module for Java Authentication and
Authorization Service. Gemplus Developer Conference, Montpellier, France, June 20–21,
2000.
6. J. Linn. Generic Security Service Application Program Interface,Version 2. Internet
Engineering Task Force, January 2000 Request for Comments 2743
7. J. Linn. The Kerberos Version 5 GSS-API Mechanism. Internet Engineering Task Force,
June 1996 Request for Comments 1964
8. [Link]. The Simple Public-Key GSS-API Mechanism (SPKM). Internet Engineering Task
Force, October 1996 Request for Comments 2025
9. J. Kabat and [Link]. Generic Security Service API Version 2: Java Bindings. Internet
Engineering Task Force, January 1997 Request for Comments 2853
10. JSR 000072 Generic Security Services API
Java SE offers a rich set of APIs and features for developing secure Java applications and
services. The exercise sessions listed here can help you to use the Java SE GSS APIs to build
applications that authenticate their users, to communicate securely with other applications and
services, and help you to configure your applications in a Kerberos environment to achieve
Single Sign-On. In addition, you will also learn how to use stronger encryption algorithms in a
Kerberos environment, and how to use Java GSS mechanisms such as SPNEGO to secure
the association.
Exercises
This session includes six lessons. Each part contains one or more coding exercises. Work
through the exercises in sequence:
• Part I : Secure Authentication using the Java Authentication and Authorization Service
(JAAS)
– Exercise 1: Using the JAAS API
– Exercise 2: Configuring JAAS for Kerberos Authentication
• Part II : Secure Communications using the Java SE Security API
– Exercise 3: Using the Java Generic Security Service (GSS) API
– Exercise 4: Using the Java SASL API
– Exercise 5: Using the Java Secure Socket Extension with Kerberos
• Part III : Deploying for Single Sign-On in a Kerberos Environment
– Exercise 6: Deploying for Single Sign-On
• Part IV : Secure Communications Using Stronger Encryption Algorithms
– Exercise 7: Configuring to Use Stronger Encryption Algorithms in a Kerberos
Environment, to Secure the Communication
• Part V : Secure Authentication Using SPNEGO Java GSS Mechanism
– Exercise 8: Using the Java Generic Security Services (GSS) API with SPNEGO
• Part VI: HTTP/SPNEGO Authentication
– Exercise 9: Using HTTP/SPNEGO Authentication
Steps to Follow
• Read the [Link] sample code. The code performs the following tasks:
1. Define a callback handler or use a predefined one.
2. Create a LoginContext with a name that identifies which JAAS configuration entry to
use.
3. Perform the authentication.
4. Define the task that the authenticated user is to perform.
5. Perform the action as the authenticated user.
6. Log out.
[Link] will run the code defined in MyAction as the authenticated user [lines
14-15]. This serves two purposes. First, code in MyAction that requires identity information
for authentication to a service could get it from the subject. This exercise demonstrates this
Summary
This exercise introduced the main classes of the JAAS APIs: LoginContext and Subject.
You learned how to use LoginContext to authenticate a user and collect its identity
information in a Subject. You then learned how to use the Subject to perform an action as the
authenticated user.
Next Steps
Proceed to Exercise 2: Configuring JAAS for Kerberos Authentication to learn how to configure
the sample application to use Kerberos for authentication.
Steps to Follow
1. Examine the [Link] configuration file.
This file contains two entries, one named client and one named server. The client entry
indicates that the LoginContext must use the
[Link].Krb5LoginModule. The server entry indicates
that the LoginContext must use the same login module, and use keys from the
[Link] file for the principal host/machineName.
2. Determine the hostname of your machine by executing the hostname command.
3. Edit this file and change the entry for server principal to use the name of your machine. For
example, if your machine name is j1hol-001, this line in the configuration file should look
like this:
principal="host/j1hol-001"
You will be prompted for a password. You should see the following output. Replace
password with a password that is secure.
Summary
In this exercise, you learned how to configure a JAAS application to use a Kerberos login
module, both as a client principal who enters his/her username/password interactively, and as
a service principal who gets its keys from a keytab file.
Next Steps
Proceed to Part II : Secure Communications using the Java SE Security API to learn how to
establish secure communication channels using Java security APIs.
Steps to Follow
1. Read the [Link] code.
This code fragment defines the action to execute after the service principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
code first creates an instance of GSSManager, which it uses to obtain its own credentials
and to create an instance of GSSContext. It uses this context to perform authentication.
Upon completing authentication, it accepts encrypted input from the client and uses the
established security context to decrypt the data. It then uses the security context to encrypt
a reply containing the original input and the date, and then sends it back to the client.
2. Compile the sample code.
3. Read the [Link] code.
This code fragment defines the action to execute after the client principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
code first creates an instance of GSSManager, which it uses to obtain a principal name for
the service that it is going to communicate with. It then creates an instance of
GSSContext to perform authentication with the service. Upon completing authentication, it
uses the established security context to encrypt a message, and sends it to the server. It
then reads an encrypted message from the server and decodes it using the established
security context.
4. Compile the sample code.
5. Launch a new window and start the server:
6. Run the client application. GssClient takes two parameters: the service name and the
name of the server that the service is running on. For example, if the service is host
running on the machine j1hol-001, you would enter the following:
Summary
In this exercise, you learned how to write a client-server application that uses the Java GSS
API to authenticate and communicate securely with each other.
Next Steps
1. Proceed to Exercise 4: Using the Java SASL API to learn how to write a client/server
application that uses the Java SASL API to authenticate and communicate securely with
each other.
2. Proceed to Exercise 5: Using the Java Secure Socket Extension with Kerberos to learn
how to write a client/server application that uses the JSSE to authenticate and
communicate securely with each other.
3. Proceed to Exercise 6: Deploying for Single Sign-On to learn how to configure the sample
programs that you have just used to achieve single sign-on in a Kerberos environment.
Steps to Follow
1. Read the [Link] sample code.
This code fragment defines the action to execute after the service principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
server specifies the quality of protections (QOP) that it will support and then creates an
instance of SaslServer to perform the authentication. The challenge-response protocol
of SASL is performed in the while loop, with the server sending challenges to the client and
processing the responses from the client. After authentication, the identity of the
authenticated client can be obtained via a call to the getAuthorizedID() method. If a
security layer was negotiated, the server can exchange data securely with the client.
2. Compile the sample code.
3. Read the [Link] sample code.
This code fragment defines the action to execute after the client principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
program first specifies the quality of protections that it wants (in this case, confidentiality)
and then creates an instance of SaslClient to use for authentication. It then checks
whether the mechanism has an initial response and if so, gets the response by invoking
the evaluateChallenge() method with an empty byte array. It then sends the response to
the server to begin the authentication. The challenge-response protocol of SASL is
performed in the while loop, with the client evaluating the challenges that it gets from the
server and sending the server the corresponding responses to the challenges. After
authentication, the client can proceed to communicate with the server using the negotiated
security layer.
4. Compile the sample code.
5. Launch a new window and start the server. SaslTestServer takes two parameters: the
service name and the name of the server that the service is running on. For example, if the
service is host running on the machine j1hol-001, you would enter the following:
6. Run the client application. SaslTestClient takes two parameters: the service name and
the name of the server that the service is running on. For example, if the service is host
running on the machine j1hol-001, you would enter the following:
Output for running the SaslTestClient example (password will be replaced by the
password that you provided):
Summary
In this exercise, you learned how to write a client-server application that uses the Java SASL
API to authenticate and communicate securely with each other.
Next Steps
1. Proceed to Exercise 5: Using the Java Secure Socket Extension with Kerberos to learn
how to write a client/server application that uses the JSSE to authenticate and
communicate securely with each other.
2. Proceed to Exercise 6: Deploying for Single Sign-On to learn how to configure the sample
programs that you have just used to achieve single sign-on in a Kerberos environment.
Steps to Follow
1. Read the [Link] sample code.
This code fragment defines the action to execute after the service principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
server first creates an SSLServerSocket. This is analogous to an application creating a
plain ServerSocket except an SSLServerSocket will provide automatic authentication,
encryption and decryption, as needed. The server then sets the cipher suites that it wants
to use. The server then runs in a loop, accepting connections from SSL clients, and reads
and writes from the SSL socket. The server can find out the identities of the owners of
socket by invoking the getLocalPrincipal() and getPeerPrincipal() methods.
2. Compile the sample code.
3. Read the [Link] sample code.
This code fragment defines the action to execute after the client principal has
authenticated to the KDC. It replaces the MyAction in Exercise 1: Using the JAAS API. The
client first creates an SSLSocket. The client then sets the cipher suites that it wants to
use. The client then exchanges messages with the server using the SSLSocket by
reading and writing to the socket's input/output streams. The client can find out the
identities of the owners of socket by invoking the getLocalPrincipal() and
getPeerPrincipal() methods.
4. Compile the sample code.
5. Launch a new window and start the server. JsseServer takes one parameter: the name of
the server that the JSSE service is running on. For example, if it is running on the machine
j1hol-001, you would enter the following:
% xterm &
% java -[Link]=[Link] JsseServer
j1hol-001
6. Run the client application. JsseClient takes one parameter: the name of the server that
the JSSE service is running on. For example, if the service is running on the machine
j1hol-001, you would enter the following.
Output for running the JsseClient example (password will be replaced by the password
that you provided):
Summary
In this exercise, you learned how to write a client-server application that uses JSSE to
authenticate and communicate securely with each other, using Kerberos as the underlying
authentication system.
Next Steps
Proceed to Exercise 6: Deploying for Single Sign-On to learn how to configure the sample
programs in Exercises 3, 4, and 5 to achieve single sign-on in a Kerberos environment.
Steps to Follow
1. Edit the [Link] configuration file.
This file contains two entries: one named client and one named server. Add the line
useTicketCache=true to the client entry.
2. Perform Kerberos login to the native operating system. To login to Kerberos, use kinit
command as follows:
% kinit test
Note
Encryption types based on DES, DES3, and RC4 are disabled by default.
The following is a list of all the encryption types supported by the Java GSS/Kerberos provider
in Java SE:
• AES256-CTS
• AES128-CTS
• AES256-SHA2
• AES128-SHA2
• RC4-HMAC
• DES3-CBC-SHA1
• DES-CBC-MD5
• DES-CBC-CRC
Steps to Follow
1. Configure the Key Distribution Center (KDC) and update the Kerberos database.
First, you need to update to use the KDC that supports the required Kerberos encryption
types.
You need to update the Kerberos database to generate the new keys with stronger
encryption algorithms. By default, Solaris 10 KDC will generate the keys for all the
encryption types previously listed. You can now create a keytab that will include all the
keys for all these encryption types.
2. Edit the Kerberos configuration file ([Link]).
You will need to edit the Kerberos configuration file in order to select the desired encryption
types used. The following lists the required parameters that you will need to insert under
the libdefaults section of the Kerberos configuration file. For the purpose of this
exercise, all the required entries have been added to a sample Kerberos configuration file
included with the exercise, and the entries have been commented out. To enable the
desired encryption type, you only need to uncomment the required entries.
• To only enable AES256-CTS encryption type, add the following:
[libdefaults]
default_tkt_enctypes = aes256-cts
default_tgs_enctypes = aes256-cts
permitted_enctypes = aes256-cts
Note
Solaris 10 11/06 and earlier does not support AES256 by default. You will
need to install the following packages: SUNWcry, SUNWcryr, SUNWcryptoint.
[libdefaults]
default_tkt_enctypes = aes128-cts
default_tgs_enctypes = aes128-cts
permitted_enctypes = aes128-cts
Note
• If these parameters are not added to the Kerberos configuration file, Solaris
10 11/06 and earlier will default to use AES128 enctype. If the exportable
crypto packages have been installed, it will default to use AES256 enctype.
• Destroy any pre-existing Kerberos TGT in the ticket cache from the previous
exercise as follows:
% kdestroy
3. Launch a new window and start the server using the updated [Link] as follows:
% java -[Link]=[Link] \
-[Link]=[Link] GSSServer
4. Run the client application using the updated [Link]. The GSSClient class takes two
parameters: the service name and the name of the server that the service is running on.
For example, if the service is host running on the machine j1hol-001, use the following
(provide a secure password when prompted):
% java -[Link]=[Link] \
-[Link]=[Link] \
GSSClient host j1hol-001
Summary
In this exercise, you learned how to write a client-server application that uses Java GSS API to
authenticate and communicate securely using stronger Kerberos encryption algorithms. You
can enable Kerberos debugging (-[Link]=true), to obtain information
about the Kerberos encryption type used.
Exercise 8: Using the Java Generic Security Services (GSS) API with SPNEGO
Java GSS is a framework that can support multiple security mechanisms; a way to negotiate a
security mechanism underneath GSS-API is needed. This is available via SPNEGO.
SPNEGO is standardized at IETF in RFC 4178. It is a pseudo-security mechanism used to
negotiate an underlying security mechanism. It provides the flexibility for client and server to
securely negotiate a common GSS security mechanism.
Microsoft makes heavy use of SPNEGO. SPNEGO can be used to inter-operate with Microsoft
Server over HTTP, to support HTTP-based cross-platform authentication via the Negotiate
Protocol.
Currently, when using Java GSS with Kerberos, we specify the Kerberos OID as follows:
In order to use SPNEGO, you only need to specify the SPNEGO OID as follows:
Then you can use the SPNEGO OID when creating a GSSCredential, GSSContext, etc.
Steps to Follow
1. Read the [Link] code.
2. Compile the sample code:
% javac [Link]
% javac [Link]
6. Run the client application. GssSpNegoClient takes two parameters: the service name and
the name of the server that the service is running on. For example, if the service is host
running on the machine j1hol-001, use the following (provide a secure password when
prompted):
% java -[Link]=[Link] \
GssSpNegoClient host j1hol-001
Sample output for running GssSpNegoClient (password is replaced with the password you
provided before):
Summary
In this exercise, you learned how to write a client-server application that uses the Java GSS
API with SPNEGO to negotiate an underlying security mechanism, such as Kerberos, and
communicate securely using Kerberos as the underlying authentication system.
Note
Microsoft has implemented certain variations of the SPNEGO protocol. Therefore, to
interoperate with Microsoft, a separate mode has been added through the system
property [Link]. This property is enabled to true by
default. To disable it, you need to explicitly set this property to false. To enable
SPNEGO debugging, you can set the system property
[Link]=true.
Web Authentication
The Web Server responds with
Proxy Authentication
The Web Server responses with
There is no new public API function involved in the new feature, but several configurations are
needed to perform a success communication:
Kerberos 5 Configuration
Since the SPNEGO mechanism will call JGSS, which in turns calls the Kerberos V5 login
module to do real works. Kerberos 5 configurations are needed. This includes the following:
• Some way to provide Kerberos configurations. This can be achieved with the Java system
property [Link]. For example:
java -[Link]=[Link] \
-[Link]=false \
ClassName
A JAAS config file denoting what login module to use. HTTP SPNEGO codes will look for
the standard entry named [Link].
For example, you can provide a file [Link]:
[Link] {
[Link].Krb5LoginModule
required useTicketCache=true;
};
java -[Link]=[Link] \
-[Link]=[Link] \
-[Link]=false \
ClassName
}
}
Note
According to the specification of [Link], it's designed to get the
user name and password at the same time, so do not specify principal=xxx in the
JAAS config file.
Scheme Preference
The client can still provide system property [Link] to denote that a certain
scheme should always be used as long as the server request for it. You can use "SPNEGO" or
"Kerberos" for this system property. "SPNEGO" means you prefer to response the Negotiate
scheme using the GSS/SPNEGO mechanism; "Kerberos" means you prefer to response the
Negotiate scheme using the GSS/Kerberos mechanism. Normally, when authenticating against
a Microsoft product, you can use "SPNEGO". The value "Kerberos" also works for Microsoft
servers. It's only needed when you encounter a server which knows Negotiate but doesn't
know about SPNEGO.
If [Link] is not set, the internal order chosen is:
Fallback
If the server has provided more than one authentication scheme (including Negotiate),
according to the processing order mentioned in the last section, Java will try to challenge the
Negotiate scheme. However, if the protocol cannot be established successfully (for example,
the Kerberos configuration is not correct, or the server's hostname is not recorded in the KDC
principal DB, or the user name and password provided by Authenticator is wrong), then the
second strongest scheme will be automatically used.
Note
If [Link] is set to SPNEGO or Kerberos, then SPNEGO assumes you
only want to try the Negotiate scheme even if it fails. SPNEGO will not fallback to any
other scheme and your program will throw an IOException saying it received a 401
or 407 error from the HTTP response.
Assume that you have an IIS Server running on a Windows Server within an Active Directory. A
web page on this server is configured to be protected by Integrated Windows Authentication.
This means the server will prompt for both Negotiate and NTLM authentication.
You need to prepare these files to get the protected file:
[Link]
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
[Link]
[libdefaults]
default_realm = [Link]
[realms]
[Link] = {
kdc = [Link]
}
[Link]
[Link] {
[Link].Krb5LoginModule required doNotPrompt=false
useTicketCache=true;
};
java -[Link]=[Link] \
-[Link]=[Link] \
-[Link]=false \
RunHttpSpnego \
[Link]
In fact, if you are running on a Windows machine as a domain user, or, you are running on
a Linux or Solaris machine that has already issued the kinit command and got the
credential cache. The class MyAuthenticator will be completely ignored, and the output
will be simply:
which shows the user name and password are not consulted. This is the so-called Single
Sign-On.
Also, you can just run
to see how the fallback is done, in which case you will see
import [Link];
import [Link].*;
import [Link];
import [Link].*;
import [Link];
import [Link];
loginAndAction(name, action);
}
try {
// Create a LoginContext with a callback handler
context = new LoginContext(name, callbackHandler);
// Perform authentication
[Link]();
} catch (LoginException e) {
[Link]("Login failed");
[Link]();
[Link](-1);
}
[Link](subject, action);
[Link]();
}
// Action to perform
static class MyAction implements PrivilegedExceptionAction {
MyAction() {
}
[Link]
client {
[Link].Krb5LoginModule required
principal="test";
};
server {
[Link].Krb5LoginModule required
useKeyTab=true
storeKey=true
keyTab=[Link]
principal="host/machineName";
};
[Link]
import [Link].*;
import [Link];
class AppConnection {
public static final int AUTH_CMD = 100;
public static final int DATA_CMD = 200;
// Client application
AppConnection(String hostName, int port) throws IOException {
socket = new Socket(hostName, port);
} catch (IOException e) {
len = 0;
}
if (len > 0) {
reply = new byte[len];
[Link](reply);
} else {
reply = new byte[0];
}
return reply;
}
[Link]();
reply = receive(-1);
}
return new AppReply(returnCode, reply);
}
int getStatus() {
return code;
}
byte[] getBytes() {
return bytes;
}
}
void close() {
try {
[Link]();
} catch (IOException e) {
}
}
}
[Link]
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link].*;
import [Link];
/**
* A sample server application that uses JGSS to do mutual authentication
* with a client using Kerberos as the underlying mechanism. It then
* exchanges data securely with the client.
*
* Every message exchanged with the client includes a 4-byte application-
* level header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
[Link]("server", action);
}
GssServerAction(int port) {
[Link] = port;
}
DataOutputStream outStream =
new DataOutputStream([Link]());
/*
* Create a GSSContext to receive the incoming request
* from the client. Use null for the server credentials
* passed in. This tells the underlying mechanism
* to use whatever credentials it has available that
* can be used to accept this connection.
*/
while (![Link]()) {
if (verbose) {
[Link]("Reading ...");
}
token = new byte[[Link]()];
if (verbose) {
[Link]("Will read input token of size " +
[Link] + " for processing by
acceptSecContext");
}
[Link](token);
if ([Link] == 0) {
if (verbose) {
[Link]("skipping zero length token");
}
continue;
}
if (verbose) {
[Link]("Token = " + getHexBytes(token));
[Link]("acceptSecContext..");
}
token = [Link](token, 0, [Link]);
[Link]([Link]);
[Link](token);
[Link]();
}
/*
* If mutual authentication did not take place, then
* only the client was authenticated to the
* server. Otherwise, both client and server were
* authenticated to each other.
*/
if ([Link]())
[Link]("Mutual authentication took place!");
/*
* Create a MessageProp which unwrap will use to return
* information such as the Quality-of-Protection that was
* applied to the wrapped token, whether or not it was
* encrypted, etc. Since the initial MessageProp values
* are ignored, just set them to the defaults of 0 and false.
*/
MessageProp prop = new MessageProp(0, false);
/*
* Read the token. This uses the same token byte array
* as that used during context establishment.
*/
token = new byte[[Link]()];
if (verbose) {
[Link]("Will read token of size " +
[Link]);
}
[Link](token);
/*
* Now generate reply that is the concatenation of the
* incoming string with the current time.
*/
/*
* First reset the QOP of the MessageProp to 0
* to ensure the default Quality-of-Protection
* is applied.
*/
[Link](0);
[Link]([Link]);
[Link](token);
[Link]();
private static final String getHexBytes(byte[] bytes, int pos, int len) {
[Link]([Link](b1));
[Link]([Link](b2));
[Link](' ');
}
return [Link]();
}
[Link]
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link];
/**
* A sample client application that uses JGSS to do mutual authentication
* with a server using Kerberos as the underlying mechanism. It then
* exchanges data securely with the server.
*
* Every message sent to the server includes a 4-byte application-level
* header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrapped token to the server.
* 3. server sends a wrapped token back to the client for the application
*
* Start GssServer first before starting GssClient.
*
* Usage: java <options> GssClient <service> <serverName>
*
* Example: java -[Link]=[Link] \
* GssClient host [Link]
*
* Add -[Link]=[Link] to specify application-specific
* Kerberos configuration (different from operating system's Kerberos
* configuration).
*/
if ([Link] < 2) {
[Link](
"Usage: java <options> GssClient <service> <serverName>");
[Link](-1);
}
PrivilegedExceptionAction action =
new GssClientAction(serverPrinc, args[1], PORT);
[Link]("client", action);
}
/*
* This Oid is used to represent the Kerberos version 5 GSS-API
* mechanism. It is defined in RFC 1964. We will use this Oid
* whenever we need to indicate to the GSS-API that it must
* use Kerberos for some purpose.
*/
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
/*
* Create a GSSName out of the server's name.
*/
GSSName serverName = [Link](serverPrinc,
GSSName.NT_HOSTBASED_SERVICE);
/*
* Create a GSSContext for mutual authentication with the
* server.
* - serverName is the GSSName that represents the server.
* - krb5Oid is the Oid that represents the mechanism to
* use. The client chooses the mechanism to use.
* - null is passed in for client credentials
* - DEFAULT_LIFETIME lets the mechanism decide how long the
* context can remain valid.
* Note: Passing in null for the credentials asks GSS-API to
* use the default credentials. This means that the mechanism
* will look among the credentials stored in the current Subject
* to find the right kind of credentials that it needs.
*/
GSSContext context = [Link](serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
while (![Link]()) {
[Link]([Link]);
[Link](token);
[Link]();
}
/*
* If mutual authentication did not take place, then only the
* client was authenticated to the server. Otherwise, both
* client and server were authenticated to each other.
*/
if ([Link]())
[Link]("Mutual authentication took place!");
/*
* The first MessageProp argument is 0 to request
* the default Quality-of-Protection.
* The second argument is true to request
* privacy (encryption of the message).
*/
MessageProp prop = new MessageProp(0, true);
/*
* Encrypt the data and send it across. Integrity protection
* is always applied, irrespective of confidentiality
* (i.e., encryption).
* You can use the same token (byte array) as that used when
* establishing the context.
*/
/*
* Now we will allow the server to decrypt the message,
* append a time/date on it, and send then it back.
*/
[Link]("Done.");
[Link]();
[Link]();
return null;
}
}
private static final String getHexBytes(byte[] bytes, int pos, int len) {
[Link]([Link](b1));
[Link]([Link](b2));
[Link](' ');
}
return [Link]();
}
[Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
import [Link].*;
import [Link];
/**
* A sample server application that uses SASL to authenticate clients
* using Kerberos as the underlying mechanism. It then
* exchanges data securely with the client.
*
* This sample program uses a ficticious application-level protocol.
* Every message exchanged between the client and server an 8-byte
* header that consists of two integers: the first integer represesents
* the application-level command or status code while the second integer
* indicates the length of the SASL buffer. This header is followed by
* the SASL buffer.
*
* The protocol is:
* 1. Authentication
* a. client sends initial response to server containing
authentication
* information
* b. server accepts and evaluates response to generate challenge; it
* sends the challenge to the server.
* c. client evaluates challenge to generate response; it sends the
* response;
* d. Steps b and c are repeated until authentication succeeds or
fails.
* 2. client sends an encrypted message to the server.
* 3. server decryptes the message and sends an encrypted one back
* that contains the original message plus the current time.
*
* Start SaslTestServer first before starting SaslTestClient.
*
* Usage: java <options> SaslTestServer service serverName
*
* Example: java -[Link]=[Link] \
* SaslTestServer host [Link]
*
* Add -[Link]=[Link] to specify application-specific
* Kerberos configuration (different from operating system's Kerberos
* configuration).
*/
if ([Link] < 2) {
[Link](
"Usage: java <options> SaslTestServer <service> <host>");
[Link](-1);
}
PrivilegedExceptionAction action =
new SaslServerAction(args[0], args[1], PORT);
[Link]("server", action);
}
if (srv == null) {
throw new Exception(
"Unable to find server implementation for " + MECH);
}
while (![Link]()) {
try {
// Generate challenge based on response
byte[] challenge = [Link](response);
if ([Link]()) {
[Link]([Link], challenge);
auth = true;
} else {
clientMsg =
[Link](AppConnection.AUTH_INPROGRESS,
challenge);
response = [Link]();
}
} catch (SaslException e) {
// [Link]();
// Send failure notification to client
[Link]([Link], null);
break;
}
}
[Link]([Link], realReply);
}
return null;
}
}
if (acb != null) {
String authid = [Link]();
String authzid = [Link]();
if ([Link](authzid)) {
// Self is always authorized
[Link](true);
} else {
// Should check some database for mapping and decide.
// Current simplified policy is to reject authzids that
// don't match authid
[Link](false);
if ([Link]()) {
// Set canonicalized name.
// Should look up database for canonical names
[Link](authzid);
}
}
}
}
}
[Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
import [Link].*;
import [Link].*;
import [Link];
/**
* A sample client application that uses SASL to authenticate to
* a server using Kerberos as the underlying mechanism. It then
* exchanges data securely with the server.
*
* This sample program uses a ficticious application-level protocol.
* Every message exchanged between the client and server an 8-byte
* header that consists of two integers: the first integer represesents
* the application-level command or status code while the second integer
* indicates the length of the SASL buffer. This header is followed by
* the SASL buffer.
*
* The protocol is:
* 1. Authentication
* a. client sends initial response to server containing
authentication
* information
* b. server accepts and evaluates response to generate challenge; it
* sends the challenge to the server.
* c. client evaluates challenge to generate response; it sends the
* response;
* d. Steps b and c are repeated until authentication succeeds or
fails.
* 2. client sends an encrypted message to the server.
* 3. server decryptes the message and sends an encrypted one back
* that contains the original message plus the current time.
*
* Start SaslTestServer first before starting SaslTestClient.
*
* Usage: java <options> SaslTestClient service serverName
*
* Example: java -[Link]=[Link] \
if ([Link] < 2) {
[Link](
"Usage: java <options> SaslTestClient <service>
<serverName>");
[Link](-1);
}
PrivilegedExceptionAction action =
new SaslClientAction(args[0], args[1], PORT);
[Link]("client", action);
}
if (clnt == null) {
throw new Exception(
byte[] response;
byte[] challenge;
if ([Link]() == [Link]) {
if (response != null) {
throw new Exception("Protocol error interacting with
SASL");
}
break;
}
if ([Link]() == [Link]) {
byte[] encryptedReply = [Link]();
[Link]();
return null;
}
}
}
[Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
/*
* Tests support for RFC 2712. Specify use of only a KRB5 cipher for both
* client and server, by first doing a JAAS login for the server
* without first doing a JAAS login for the client.
*/
[Link]("server", action);
}
JsseServerAction(int port) {
[Link] = port;
}
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) [Link]();
SSLServerSocket sslServerSocket =
(SSLServerSocket) [Link](localPort);
String cipherSuiteChosen =
[Link]().getCipherSuite();
[Link]("Cipher suite in use: " +
cipherSuiteChosen);
Principal self = [Link]().getLocalPrincipal();
[Link]("I am: " + [Link]());
Principal peer = [Link]().getPeerPrincipal();
[Link]("Client is: " + [Link]());
[Link]();
}
return null;
}
}
}
[Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
import [Link];
if ([Link] < 1) {
[Link](
"Usage: java <options> JsseClient <serverName>");
[Link](-1);
}
[Link]("client", action);
}
String cipherSuiteChosen =
[Link]().getCipherSuite();
[Link]("Cipher suite in use: " + cipherSuiteChosen);
Principal self = [Link]().getLocalPrincipal();
[Link]("I am: " + [Link]());
Principal peer = [Link]().getPeerPrincipal();
[Link]("Server is: " + [Link]());
[Link]();
return null;
}
}
}
[Link]
# [Link] template
# In order to complete this configuration file
# you will need to replace the __<name>__ placeholders
# with appropriate values for your network.
#
[libdefaults]
default_realm = [Link]
forwardable = true
default_tkt_enctypes = aes128-cts
default_tgs_enctypes = aes128-cts
permitted_enctypes = aes128-cts
[realms]
[Link] = {
kdc = j1hol-1280
kdc = j1hol-004
admin_server = j1hol-1280
}
[domain_realm]
.[Link] = [Link]
[logging]
default = FILE:/var/krb5/[Link]
kdc = FILE:/var/krb5/[Link]
kdc_rotate = {
# frequently.
period = 1d
versions = 10
}
[appdefaults]
gkadmin = {
help_url = [Link]
}
kinit = {
renewable = true
forwardable= true
}
rlogin = {
forwardable= true
}
rsh = {
forwardable= true
}
telnet = {
autologin = true
forwardable= true
}
[Link]
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link];
/**
* A sample client application that uses JGSS to do mutual authentication
* with a server using Kerberos as the underlying mechanism. It then
* exchanges data securely with the server.
*
* Every message sent to the server includes a 4-byte application-level
* header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrapped token to the server.
* 3. server sends a wrapped token back to the client for the application
*
* Start GssServer first before starting GssClient.
*
* Usage: java <options> GssSpNegoClient <service> <serverName>
*
* Example: java -[Link]=[Link] \
* GssSpNegoClient host [Link]
*
* Add -[Link]=[Link] to specify application-specific
* Kerberos configuration (different from operating system's Kerberos
* configuration).
*/
if ([Link] < 2) {
[Link](
"Usage: java <options> GssSpNegoClient <service>
<serverName>");
[Link](-1);
}
PrivilegedExceptionAction action =
new GssClientAction(serverPrinc, args[1], PORT);
[Link]("client", action);
}
[Link]());
/*
* This Oid is used to represent the SPNEGO GSS-API
* mechanism. It is defined in RFC 2478. We will use this Oid
* whenever we need to indicate to the GSS-API that it must
* use SPNEGO for some purpose.
*/
Oid spnegoOid = new Oid("[Link].5.5.2");
/*
* Create a GSSName out of the server's name.
*/
GSSName serverName = [Link](serverPrinc,
GSSName.NT_HOSTBASED_SERVICE, spnegoOid);
/*
* Create a GSSContext for mutual authentication with the
* server.
* - serverName is the GSSName that represents the server.
* - krb5Oid is the Oid that represents the mechanism to
* use. The client chooses the mechanism to use.
* - null is passed in for client credentials
* - DEFAULT_LIFETIME lets the mechanism decide how long the
* context can remain valid.
* Note: Passing in null for the credentials asks GSS-API to
* use the default credentials. This means that the mechanism
* will look among the credentials stored in the current Subject
* to find the right kind of credentials that it needs.
*/
GSSContext context = [Link](serverName,
spnegoOid,
null,
GSSContext.DEFAULT_LIFETIME);
while (![Link]()) {
if (verbose) {
[Link]("Will send token of size " +
[Link] + " from initSecContext.");
[Link]("writing token = " +
getHexBytes(token));
}
[Link]([Link]);
[Link](token);
[Link]();
}
/*
* If mutual authentication did not take place, then only the
* client was authenticated to the server. Otherwise, both
* client and server were authenticated to each other.
*/
if ([Link]())
[Link]("Mutual authentication took place!");
/*
* The first MessageProp argument is 0 to request
* the default Quality-of-Protection.
* The second argument is true to request
* privacy (encryption of the message).
*/
MessageProp prop = new MessageProp(0, true);
/*
* Encrypt the data and send it across. Integrity protection
* is always applied, irrespective of confidentiality
* (i.e., encryption).
* You can use the same token (byte array) as that used when
* establishing the context.
*/
/*
* Now we will allow the server to decrypt the message,
* append a time/date on it, and send then it back.
*/
[Link]("Done.");
[Link]();
[Link]();
return null;
}
}
private static final String getHexBytes(byte[] bytes, int pos, int len) {
[Link]([Link](b1));
[Link]([Link](b2));
[Link](' ');
}
return [Link]();
}
[Link]
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link].*;
import [Link];
/**
* A sample server application that uses JGSS to do mutual authentication
* with a client using Kerberos as the underlying mechanism. It then
* exchanges data securely with the client.
*
* Every message exchanged with the client includes a 4-byte application-
* level header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
* 3. server sends a wrap token back to the client.
*
* Start GssSpNegoServer first before starting GssClient.
*
* Usage: java <options> GssSpNegoServer
*
* Example: java -[Link]=[Link] \
* GssSpNegoServer
*
* Add -[Link]=[Link] to specify application-specific
* Kerberos configuration (different from operating system's Kerberos
* configuration).
*/
[Link]("server", action);
}
GssServerAction(int port) {
[Link] = port;
}
DataOutputStream outStream =
new DataOutputStream([Link]());
/*
* Create a GSSContext to receive the incoming request
* from the client. Use null for the server credentials
* passed in. This tells the underlying mechanism
* to use whatever credentials it has available that
* can be used to accept this connection.
*/
while (![Link]()) {
if (verbose) {
[Link]("Reading ...");
}
token = new byte[[Link]()];
if (verbose) {
[Link]("Will read input token of size " +
[Link] + " for processing by
acceptSecContext");
}
[Link](token);
if ([Link] == 0) {
if (verbose) {
[Link]("skipping zero length token");
}
continue;
}
if (verbose) {
[Link]("Token = " + getHexBytes(token));
[Link]("acceptSecContext..");
}
token = [Link](token, 0, [Link]);
[Link]([Link]);
[Link](token);
[Link]();
}
}
/*
* If mutual authentication did not take place, then
* only the client was authenticated to the
* server. Otherwise, both client and server were
* authenticated to each other.
*/
if ([Link]())
[Link]("Mutual authentication took place!");
/*
* Create a MessageProp which unwrap will use to return
* information such as the Quality-of-Protection that was
* applied to the wrapped token, whether or not it was
* encrypted, etc. Since the initial MessageProp values
* are ignored, just set them to the defaults of 0 and false.
*/
MessageProp prop = new MessageProp(0, false);
/*
* Read the token. This uses the same token byte array
* as that used during context establishment.
*/
token = new byte[[Link]()];
if (verbose) {
[Link]("Will read token of size " +
[Link]);
}
[Link](token);
/*
* Now generate reply that is the concatenation of the
* incoming string with the current time.
*/
/*
* First reset the QOP of the MessageProp to 0
* to ensure the default Quality-of-Protection
* is applied.
*/
[Link](0);
[Link]([Link]);
[Link](token);
[Link]();
private static final String getHexBytes(byte[] bytes, int pos, int len) {
[Link]([Link](b1));
[Link]([Link](b2));
[Link](' ');
}
return [Link]();
}
% java -[Link]=[Link]\
-[Link]=[Link] Jaas client
The Generic Security Services Application Program Interface (GSS-API) mechanism is defined
by RFC 1964 and supplemented with RFC 4121 under the Internet Standards process.
Note
The AES-128 and AES-256 encryption types are enabled by default. The following
legacy encryption types are disabled by default:
• DES-based encryption types, including des-cbc-crc and dec-cbc-md5
• The DES3-based encryption type, des3-cbc-sha1
• The RC4-based encryption type, arcfour-hmac-md5 (alias rc4-hmac)
A user can restrict the usage of encryption for various purposes in [Link], in the
[libdefaults] section.
include FILENAME
includedir DIRNAME
[libdefaults]
allow_weak_crypto
ap_req_checksum_type
clockskew
default_checksum
default_keytab_name
default_realm
default_tgs_enctypes
default_tkt_enctypes
dns_fallback
dns_lookup_kdc
dns_lookup_realm
extra_addresses
forwardable
kdc_default_options
kdc_timeout
max_retries
no_addresses
noaddresses
permitted_enctypes
proxiable
renew_lifetime
renewable
safe_checksum_type
ticket_lifetime
udp_preference_limit
[realms]
[Link] = {
kdc
kdc_timeout
udp_preference_limit
max_retries
}
[capaths]
A = {
I = .
B = I
}
[domain_realm]
domain=REALM
The following are the default values for [Link] file parameters:
allow_weak_crypto = false
clockskew = 300
dns_lookup_kdc = true
dns_lookup_realm = false
forwardable = false
kdc_timeout = 30s
max_retries = 3
no_addresses = true
noaddresses = true
proxiable = false
renewable = false
udp_preference_limit = 1465
If no [Link] file is found or a setting doesn't exist in a [Link] file, then these default
values will be used. For example, a DNS lookup will be performed to fetch KDC details
because the default value of dns_lookup_kdc is true.
Introduction to JSSE
Data that travels across a network can easily be accessed by someone who is not the intended
recipient. When the data includes private information, such as passwords and credit card
numbers, steps must be taken to make the data unintelligible to unauthorized parties. It is also
important to ensure that the data has not been modified, either intentionally or unintentionally,
during transport. The Transport Layer Security (TLS) protocol was designed to help protect the
privacy and integrity of data while it is being transferred across a network.
The Java Secure Socket Extension (JSSE) enables secure Internet communications. It
provides a framework and an implementation for a Java version of the TLS protocol and
includes functionality for data encryption, server authentication, message integrity, and optional
client authentication. Using JSSE, developers can provide for the secure passage of data
between a client and a server running any application protocol (such as HTTP, Telnet, or FTP)
over TCP/IP.
By abstracting the complex underlying security algorithms and handshaking mechanisms,
JSSE minimizes the risk of creating subtle but dangerous security vulnerabilities. Furthermore,
it simplifies application development by serving as a building block that developers can
integrate directly into their applications.
JSSE provides both an application programming interface (API) framework and an
implementation of that API. The JSSE API supplements the core network and cryptographic
services defined by the [Link] and [Link] packages by providing extended
networking socket classes, trust managers, key managers, SSL contexts, and a socket factory
framework for encapsulating socket creation behavior. Because the SSLSocket class is based
on a blocking I/O model, the Java Development Kit (JDK) includes a nonblocking SSLEngine
class to enable implementations to choose their own I/O methods.
The JSSE API supports the following security protocols:
• DTLS: versions 1.0 and 1.2
• TLS: version 1.0, 1.1, 1.2, and 1.3
• SSL (Secure Socket Layer): version 3.0
These security protocols encapsulate a normal bidirectional stream socket, and the JSSE API
adds transparent support for authentication, encryption, and integrity protection.
JSSE is a security component of the Java SE platform, and is based on the same design
principles found elsewhere in the Java Cryptography Architecture (JCA) Reference Guide
framework. This framework for cryptography-related security components allows them to have
• Factories for creating sockets, server sockets, SSL sockets, and SSL server sockets. By
using socket factories, you can encapsulate socket creation and configuration behavior.
• A class representing a secure socket context that acts as a factory for secure socket
factories and engines.
• Key and trust manager interfaces (including X.509-specific key and trust managers), and
factories that can be used for creating them.
• A class for secure HTTP URL connections (HTTPS).
SunJSSE Provider
Oracle's implementation of Java SE includes a JSSE provider named SunJSSE, which comes
preinstalled and preregistered with the JCA. This provider supplies the following cryptographic
services:
• An implementation of the SSL 3.0, TLS (versions 1.0, 1.1, 1.2, and 1.3), and DTLS
(versions 1.0 and 1.2) security protocols.
• An implementation of the most common TLS and DTLS cipher suites. This implementation
encompasses a combination of authentication, key agreement, encryption, and integrity
protection.
• An implementation of an X.509-based key manager that chooses appropriate
authentication keys from a standard JCA keystore.
• An implementation of an X.509-based trust manager that implements rules for certificate
chain validation.
See The SunJSSE Provider.
Java SE Security
• The Java SE Security home page
• The Security Features in Java SE trail of the Java Tutorial
• Java PKI Programmer's Guide
• Inside Java 2 Platform Security, Second Edition: Architecture, API Design and
Implementation
Note
When using raw SSLSocket or SSLEngine classes, you should always check the peer's
credentials before sending any data. Since JDK 7, endpoint identification/verification
procedures can be handled during SSL/TLS handshaking. See the method
[Link].
For example, the host name in a URL should match the host name in the peer's
credentials. An application could be exploited with URL spoofing if the host name is
not verified.
Secure socket factories encapsulate the details of creating and initially configuring secure
sockets. This includes authentication keys, peer certificate validation, enabled cipher suites,
and the like.
The [Link] class is analogous to the SSLSocketFactory
class, but is used specifically for creating server sockets.
Obtaining an SSLSocketFactory
The following ways can be used to obtain an SSLSocketFactory:
Note
Due to the complexity of the SSL and TLS protocols, it is difficult to predict whether
incoming bytes on a connection are handshake or application data, and how that data
might affect the current connection state (even causing the process to block). In the
Oracle JSSE implementation, the available() method on the object obtained by
[Link]() returns a count of the number of application data bytes
successfully decrypted from the SSL connection but not yet read by the application.
Obtaining an SSLSocket
Instances of SSLSocket can be obtained in one of the following ways:
Protocols such as HTTPS (HTTP Over TLS) do require host name verification. Since JDK 7,
the HTTPS endpoint identification is enforced during handshaking for HttpsURLConnection
by default. See the [Link] method.
Alternatively, applications can use the HostnameVerifier interface to override the default
HTTPS host name rules. See HostnameVerifier Interface and HttpsURLConnection Class.
SSLEngine Class
As mentioned previously, TLS/DTLS are standard protocols for secure network
communications, and are being used in a wide variety of applications across a wide range of
computing platforms and devices. Along with this popularity come demands to use TLS/DTLS
with different I/O and threading models to satisfy the applications' performance, scalability,
footprint, and other requirements. There are demands to use TLS/DTLS with blocking and
nonblocking I/O channels, asynchronous I/O, arbitrary input and output streams, and byte
buffers. There are demands to use it in highly scalable, performance-critical environments,
requiring management of thousands of network connections.
Abstracting the I/O transport mechanism using the SSLEngine class in Java SE allows
applications to use the TLS/DTLS protocols in a transport-independent way, and thus frees
application developers to choose transport and computing models that best meet their needs.
Not only does this abstraction allow applications to use nonblocking I/O channels and other I/O
models, it also accommodates different threading models. This effectively leaves the I/O and
threading decisions up to the application developer. Because of this flexibility, the application
developer must manage I/O and threading (complex topics in and of themselves), as well as
have some understanding of the TLS/DTLS protocols. Because the SSLEngine class requires
an understanding of SSL/TLS, I/O, and threading models, it is considered an advanced API:
beginners should use SSLSocket.
Users of other Java programming language APIs such as the Java Generic Security Services
(Java GSS-API) and the Java Simple Authentication Security Layer (Java SASL) will notice
similarities in that the application is also responsible for transporting data.
Calls to SSLEngine produce and consume TLS/DTLS packets, which must then be exchanged
with the peer. The nomenclature for SSLEngine data is always from the perspective of the local
side: data bound for the peer is called outbound data, and the peer's data for the local side is
called inbound data. Before application data can be produced/consumed from the application
buffers, a handshaking procedure that negotiates security parameters must complete. The
handshake data that is produced/consumed is internal to SSLEngine and must be exchanged
with the peer before application data will be produced/consumed. The application is
responsible for all data transportation.
The application, shown on the left, supplies application (plaintext) data in an application buffer
and passes it to SSLEngine. After handshaking has completed and cryptographic parameters
have been negotiated, the SSLEngine object consumes the data contained in the outbound
application data buffer to produce TLS/DTLS encoded data and places it in the network buffer
supplied by the application. The application is now responsible for sending the contents of the
outbound network buffer to the peer using the transport mechanism. Upon receiving TLS/DTLS
encoded data from its peer (via the transport), the application places the inbound data into a
network buffer and passes it to SSLEngine. The SSLEngine object processes the network
buffer's contents to produce application data (or handshake data, which is consumed
internally).
An instance of the SSLEngine class can be in one of the following states:
Creation
The SSLEngine has been created and initialized, but has not yet been used. During this phase,
an application may set any SSLEngine-specific settings (enabled cipher suites, whether the
SSLEngine should handshake in client or server mode, and so on). Once handshaking has
begun, though, any new settings (except client/server mode) will be used for the next
handshake.
Initial handshaking
The initial handshake is a procedure by which the two peers exchange communication
parameters until an SSLSession is established. Application data can’t be sent during this
phase.
Application data
After the communication parameters have been established and the handshake is complete,
application data can flow through the SSLEngine. Outbound application messages are
encrypted and integrity protected, and inbound messages reverse the process.
Rehandshaking
Either side can request a renegotiation of the session at any time during the Application Data
phase. New handshaking data can be intermixed among the application data. Before starting
the rehandshake phase, the application may reset the TLS/DTLS communication parameters
such as the list of enabled cipher suites and whether to use client authentication, but can not
change between client/server modes. As before, after handshaking has begun, any new
SSLEngine configuration settings won’t be used until the next handshake.
Closure
When the connection is no longer needed, the application should close the SSLEngine and
should send/receive any remaining messages to the peer before closing the underlying
transport mechanism. Once an engine is closed, it is not reusable: a new SSLEngine must be
created.
SSLEngine Methods
There are three types of SSLEngine methods: those that initialize the SSLEngine and start
the handshake, those that process data packets for writing to or reading from the network, and
those that properly close the SSLEngine and connection.
The following steps describe the handshake process with respect to the methods of
SSLEngine:
1. After you have created the SSLEngine, call the various set* methods to configure all
aspects of the connection that is about to occur (for example, setEnabledProtocols(),
setEnabledCipherSuites(), setUseClientMode(), and
setWantClientAuth()). You can also configure the connection with the
SSLParameters class, which enables you to set multiple settings in a single method call.
2. Obtain the currently empty SSLSession for the SSLEngine, then determine the
maximum buffer sizes for the application and network bytes that could be generated with
the getApplicationBufferSize() and getPacketBufferSize() methods.
Allocate ByteBuffer instances for application and network buffers accordingly.
3. Once you have configured the connection and the buffers, call the beginHandshake()
method, which moves the SSLEngine into the initial handshaking state.
4. Create the transport mechanism that the connection will use with, for example, the
SocketChannel or Socket classes.
5. Call the wrap() and unwrap() methods to perform the initial handshaking. You'll need to
call these methods several times before application data can be consumed, produced, and
properly protected by later wrap()/unwrap() calls.
The handshake bytes must be exchanged with the peer using the transport mechanism.
For more information about the TLS handshaking mechanism, see one of the TLS RFCs
(such as RFC 5246: The Transport Layer Security (TLS) Protocol: Version 1.2).
For example, if your SSLEngine is acting as a client and handshaking using TLSv1.2,
then you might see the following occurring:
a. The wrap() method produces a TLS ClientHello message, then places it in the
outbound network buffer. The application must correctly send the bytes of this
message to the peer.
b. The SSLEngine must now process the peer's response (such as the ServerHello,
Certificate, and ServerHelloDone messages) to drive the handshake forward. The
application obtains the response bytes from the network transport and places them in
the inbound network buffer. The SSLEngine processes these bytes using the
unwrap() method.
c. The SSLEngine sends more handshaking data (such as the ChangeCipherSuite and
Finished messages). The wrap() places the bytes of the message in the outbound
network buffer. The application must correctly send these bytes to the peer as before.
d. The SSLEngine waits for its peer's ChangeCipherSuite or Finished message. The
bytes of this message follow the same path as in Step b.
6. Once the handshaking has completed, application data can now start flowing. Call the
wrap() method to take the bytes from the outbound application buffer, encrypt and protect
them, and then place them in the network buffer for transport to the peer. Likewise, call the
unwrap() method to decrypt and unprotect inbound network data. The resulting
application data is placed in the inbound application data buffer.
7. Once data has been exchanged between the two peers, close both the inbound and
outbound sides of the SSLEngine. Call the closeOutbound() method to signal the
SSLEngine that the application will not be sending any more data. Call the
closeInbound() method to signal the SSLEngine that the network connection has been
closed and there will be no more data.
OK
There was no error.
CLOSED
The operation closed the SSLEngine or the operation could not be completed because it was
already closed.
BUFFER_UNDERFLOW
The input buffer had insufficient data to process, indicating that the application must obtain
more data from the peer (for example, by reading more data from the network) and try the
operation again.
BUFFER_OVERFLOW
The output buffer had insufficient space to hold the result, indicating that the application must
clear or enlarge the destination buffer and try the operation again.
Example 8-1 illustrates how to handle the BUFFER_UNDERFLOW and BUFFER_OVERFLOW statuses of
the [Link]() method. It uses [Link]() and
[Link]() to determine how large to make the byte buffers.
FINISHED
The SSLEngine has just finished handshaking.
NEED_TASK
The SSLEngine needs the results of one (or more) delegated tasks before handshaking can
continue.
NEED_UNWRAP
The SSLEngine needs to receive data from the remote side before handshaking can continue.
NEED_UNWRAP_AGAIN
The SSLEngine needs to unwrap before handshaking can continue. This value indicates that
not-yet-interpreted data has been previously received from the remote side and does not need
to be received again; the data has been brought into the JSSE framework but has not been
processed yet.
NEED_WRAP
The SSLEngine must send data to the remote side before handshaking can continue, so
[Link]() should be called.
NOT_HANDSHAKING
The SSLEngine is not currently handshaking.
Having two statuses per result allows the SSLEngine to indicate that the application must take
two actions: one in response to the handshaking and one representing the overall status of the
wrap() and unwrap() methods. For example, the engine might, as the result of a single
[Link]() call, return [Link] to indicate that the input data
was processed successfully and [Link].NEED_UNWRAP to indicate
that the application should obtain more TLS/DTLS encoded data from the peer and supply it to
[Link]() again so that handshaking can continue. As you will see, the following
examples are greatly simplified; they would need to be expanded significantly to properly
handle all of these status combinations.
Example 8-2 and Example 8-3 illustrate how to process handshaking data by checking
handshaking status and the overall status of the wrap() and unwrap() methods.
case BUFFER_OVERFLOW:
// Maybe need to enlarge the peer application data buffer if
// it is too small, and be sure you've compacted/cleared the
// buffer from any previous operations.
if ([Link]().getApplicationBufferSize() >
[Link]()) {
// enlarge the peer application data buffer
} else {
// compact or clear the buffer
}
// retry the operation
break;
case BUFFER_UNDERFLOW:
// Not enough inbound data to process. Obtain more network data
// and retry the operation. You may need to enlarge the peer
// network packet buffer, and be sure you've compacted/cleared
// the buffer from any previous operations.
if ([Link]().getPacketBufferSize() >
[Link]()) {
// enlarge the peer network packet buffer
} else {
// compact or clear the buffer
}
// obtain more inbound network data and then retry the operation
break;
Example 8-2 Sample Code for Checking and Processing Handshaking Statuses and
Overall Statuses
The following code sample illustrates how to process handshaking data by checking
handshaking status and the overall status of the wrap() and unwrap() methods:
// Begin handshake
[Link]();
[Link] hs = [Link]();
switch (hs) {
case NEED_UNWRAP:
// Receive handshaking data from peer
if ([Link](peerNetData) < 0) {
// The channel has reached end-of-stream
}
// Check status
switch ([Link]()) {
case OK :
// Handle OK status
break;
case NEED_WRAP:
// Ensure that any previous net data in myNetData has been sent
// to the peer (not shown here), then generate more.
// Check status
switch ([Link]()) {
case OK :
[Link]();
case NEED_TASK :
// Handle blocking tasks
break;
Example 8-3 Sample Code for Handling DTLS handshake Status and Overall Status
The following code sample illustrates how to handle DTLS handshake status:
Before you use an SSLEngine object, you must configure the engine to act as a client or a
server, and set other configuration parameters, such as which cipher suites to use and whether
client authentication is required.
Example 8-4 Sample Code for Creating an SSLEngine Client for TLS with JKS as
Keystore
The following sample code creates an SSLEngine client for TLS that uses JKS as keystore.
Note
In this sample, the server name and port number are not used for communicating with
the server (all transport is the responsibility of the application). They are hints to the
JSSE provider to use for TLS session caching.
import [Link].*;
import [Link].*;
// Use as client
[Link](true);
Performing TLS Handshake, Then Processing TLS Data, With [Link]() and
[Link]()
Each SSLEngine object has several phases during its lifetime. Before application data can be
sent or received, the TLS protocol requires a handshake to establish cryptographic
parameters. This handshake requires a series of back-and-forth steps by the SSLEngine object.
During the initial handshaking, the wrap() and unwrap() methods generate and consume
handshake data before starting to exchange application data.
The application is responsible for reliably transporting the data (for example, by using TCP) to
and from the peer. That is, your application (and not SSLEngine) must reliably deliver to the
peer any data generated by the wrap() method, and your application (and not SSLEngine) must
reliably obtain data from the peer so that it can decode it by calling the unwrap() method.
Each SSLEngine operation generates an instance of the SSLEngineResult class, in which the
[Link] field is used to determine what operation must occur next
to move the handshake along.
When handshaking is complete, further calls to wrap() will attempt to consume application
data and package it for transport. The unwrap() method will attempt the opposite.
To send data to the peer, the application first supplies the data that it wants to send via
[Link]() to obtain the corresponding TLS encoded data. The application then sends
the encoded data to the peer using its chosen transport mechanism. When the application
receives the TLS encoded data from the peer via the transport mechanism, it supplies this data
to the SSLEngine via [Link]() to obtain the plaintext data sent by the peer.
Figure 8-3 shows the state machine during a typical TLS handshake, with corresponding
messages and statuses:
Note
In the wrap(ByteBuffer src, ByteBuffer dst) method, the parameter src is the
application data buffer and dst is the network data buffer. Conversely, in the
unwrap(ByteBuffer src, ByteBuffer dst) method, the parameter src is the
network data buffer and dst is the application data buffer. Both wrap() and
unwrap() return an instance of SSLEngineResult, which contains a
[Link] field that indicates whether the handshake is
complete or what must occur next to move the handshake along.
2. In a loop, call wrap() and unwrap() on the client and server as follows, until the handshake
is complete and both the client and server have sent their application data to each other:
a. Call wrap() on the client and the server. Check the value of the
[Link] field in the SSLEngineResult instance that wrap()
returns:
• If the handshake isn't complete, then the parameter dst will contain handshake
data that has to be sent over the network to the peer.
• If the handshake is complete, then dst will contain application data encrypted by
SSLEngine, ready to be sent to the remote peer.
b. Add code to handle the [Link] value returned by the
wrap() and unwrap() methods. See Understanding SSLEngine Operation Statuses for
more information.
c. If the wrap() method generated data in the network data buffer (which can contain
either handshake data or encrypted application data), then send it over the network to
the remote peer.
Note
• It is the responsibility of your application, not SSLEngine, to send data in
the network data buffer to the remote peer.
• After you call wrap(), you must ensure that all data in the network data
buffer has been sent to the peer.
For example, Example 8-2 sends network data to the remote peer by calling
[Link](). It checks that all network data has been sent by
calling [Link]():
while ([Link]()) {
[Link](myNetData);
}
d. Obtain network data sent over the network by the remote peer. Note that it's the
responsibility of your application, not SSLEngine, to do this. For example, Example 8-2
obtains network data from the remote peer by calling [Link]():
case NEED_UNWRAP:
// Receive handshaking data from peer
if ([Link](peerNetData) < 0) {
// The channel has reached end-of-stream
}
e. With the network data obtained from the remote peer, call unwrap() on the client and
the server. Check the value of the [Link] field in the
SSLEngineResult instance that unwrap() returns:
• If the handshake isn't complete, then the src parameter may contain additional
handshake packets, or more packets will need to be obtained from the peer to
continue the handshake.
• If the handshake is complete, then dst may contain application data decrypted by
SSLEngine, ready to be processed by the application.
f. Ensure that the client and server handles the [Link]
value returned by unwrap().
Example 8-5 Sample Code for Creating a Nonblocking SocketChannel
The following example is an SSL application that uses a non-blocking SocketChannel to
communicate with its peer. It sends the string "hello" to the peer by encoding it using the
SSLEngine created in Example 8-4 . It uses information from the SSLSession to determine how
large to make the byte buffers.
Note
The example can be made more robust and scalable by using a Selector with the
nonblocking SocketChannel.
// Complete connection
while (![Link]()) {
// do something until connect completed
}
// Do initial handshake
doHandshake(socketChannel, engine, myNetData, peerNetData);
[Link]("hello".getBytes());
[Link]();
while ([Link]()) {
// Generate TLS/DTLS encoded data (handshake or application data)
SSLEngineResult res = [Link](myAppData, myNetData);
Example 8-6 Sample Code for Reading Data From Nonblocking SocketChannel
SocketChannelSSLEngineExample 8-4
if ([Link]() == [Link]) {
[Link]();
if ([Link]()) {
// Use peerAppData
}
}
Note
The server name and port number are not used for communicating with the server (all
transport is the responsibility of the application). They are hints to the JSSE provider to
use for DTLS session caching, and for Kerberos-based cipher suite implementations
to determine which server credentials should be obtained.
Example 8-7 Sample Code for Creating an SSLEngine Client for DTLS with PKCS12 as
Keystore
The following sample code creates an SSLEngine client for DTLS that uses PKCS12 as
keystore:
import [Link].*;
import [Link].*;
Example 8-8 Sample Code for Creating an SSLEngine Server for DTLS with PKCS12 as
Keystore
SSLEngine
import [Link].*;
import [Link].*;
A DTLS handshake and a TLS handshake generate and process data similarly. (See
Generating and Processing TLS Data.) They both use the [Link]() and
[Link]() methods to generate and consume network data, respectively.
The following diagram shows the state machine during a typical DTLS handshake, with
corresponding messages and statuses:
Example 8-9 Sample Code for Handling DTLS Handshake Status and Overall Status
This sample demonstrates how to handle DTLS handshake status (from the
[Link] method) and overall status (from the
[Link] method).
Note
Each record produced by [Link]() should comply to the maximum packet
size limitation as specified by [Link]().
Note
In a DTLS engine, only handshake messages must be properly exchanged.
Application data can handle packet loss without the need for timers.
Note
In DTLS handshaking retransmission, the determined handshake status isn’t
necessarily HandshakeStatus.NEED_WRAP for the call to [Link]().
4. Call [Link]().
5. The wrapped packets are delivered.
Note
For HandshakeStatus.NEED_UNWRAP_AGAIN status, no additional data from the
network is required for an [Link]() operation.
5. Determine the handshake status for further processing. The handshake status can be
HandshakeStatus.NEED_UNWRAP_AGAIN, HandshakeStatus.NEED_UNWRAP, or
HandshakeStatus.NEED_WRAP.
if ([Link]() == [Link].NEED_TASK) {
Runnable task;
while ((task = [Link]()) != null) {
new Thread(task).start();
}
}
The SSLEngine will block future wrap() and unwrap() calls until all of the outstanding tasks are
completed.
In addition to orderly shutdowns, there can also be unexpected shutdowns when the transport
link is severed before close messages are exchanged. In the previous examples, the
application might get -1 or IOException when trying to read from the nonblocking
SocketChannel, or get IOException when trying to write to the non-blocking SocketChannel.
When you get to the end of your input data, you should call [Link](), which will
verify with the SSLEngine that the remote peer has closed cleanly from the TLS/DTLS
perspective. Then the application should still try to shut down cleanly by using the procedure in
Example 8-10. Obviously, unlike SSLSocket, the application using SSLEngine must deal with
more state transitions, statuses, and programming. See Sample Code Illustrating the Use of an
SSLEngine.
Example 8-10 Sample Code for Shutting Down a SSL/TLS/DTLS Connection
The following code sample illustrates how to shut down a TLS/DTLS connection:
while (![Link]()) {
// Get close message
SSLEngineResult res = [Link](empty, myNetData);
// Close transport
[Link]();
supported by the local implementation and the peer. The getRequestedServerNames() method
called on an ExtendedSSLSession instance is used to obtain a list of SNIServerName objects in
the requested Server Name Indication (SNI) Extension. The server should use the requested
server names to guide its selection of an appropriate authentication certificate, and/or other
aspects of the security policy. The client should use the requested server names to guide its
endpoint identification of the peer's identity, and/or other aspects of the security policy.
Calls to the getPacketBufferSize() and getApplicationBufferSize() methods on
SSLSession are used to determine the appropriate buffer sizes used by SSLEngine.
Note
The TLS protocols specify that implementations are to produce packets containing at
most 16 kilobytes (KB) of plain text. However, some implementations violate the
specification and generate large records up to 32 KB. If the [Link]() code
detects large inbound packets, then the buffer sizes returned by SSLSession will be
updated dynamically. Applications should always check the BUFFER_OVERFLOW
and BUFFER_UNDERFLOW statuses and enlarge the corresponding buffers if
necessary. See Understanding SSLEngine Operation Statuses. SunJSSE will always
send standard compliant 16 KB records and allow incoming 32 KB records. For a
workaround, see the System property [Link] in
Customizing JSSE.
HttpsURLConnection Class
The [Link] class extends the [Link]
class and adds support for HTTPS-specific features.
The HTTPS protocol is similar to HTTP, but HTTPS first establishes a secure channel through
TLS sockets and then verifies the identity of the peer (see Cipher Suite Choice and Remote
Entity Verification) before requesting or receiving data. The
[Link] class extends the [Link] class
and adds support for HTTPS-specific features. To know more about how HTTPS URLs are
constructed and used, see [Link], [Link],
[Link], and [Link] classes.
Upon obtaining an HttpsURLConnection instance, you can configure a number of HTTP and
HTTPS parameters before actually initiating the network connection via the
[Link]() method. Of particular interest are:
Note
Changing the default static SSLSocketFactory has no effect on existing instances of
HttpsURLConnection. A call to the setSSLSocketFactory() method is necessary to
change the existing instances.
You can obtain the per-instance or per-class SSLSocketFactory by making a call to the
getSSLSocketFactory() or getDefaultSSLSocketFactory() method, respectively.
1 Starting with JDK 8u31, the SSLv3 protocol (Secure Socket Layer) has been deactivated and is not available by
default. See the [Link] property [Link] in the
<java_home>/conf/security/[Link] file. If SSLv3 is absolutely required, the protocol can be
reactivated by removing SSLv3 from the [Link] property in the
[Link] file or by dynamically setting this Security Property before JSSE is initialized.
SSLContext Class
The [Link] class is an engine class for an implementation of a secure
socket protocol. An instance of this class acts as a factory for SSLSocket, SSLServerSocket,
and SSLEngine. An SSLContext object holds all of the state information shared across all
objects created under that context. For example, session state is associated with the
SSLContext when it is negotiated through the handshake protocol by sockets created by socket
factories provided by the context. These cached sessions can be reused and shared by other
sockets created under the same context.
Each instance is configured through its init method with the keys, certificate chains, and
trusted root CA certificates that it needs to perform authentication. This configuration is
provided in the form of key and trust managers. These managers provide support for the
authentication and key agreement aspects of the cipher suites supported by the context.
Currently, only X.509-based managers are supported.
• The simplest way is to call the static [Link] method on either the
SSLSocketFactory or SSLServerSocketFactory class. This method creates a default
SSLContext with a default KeyManager, TrustManager, and SecureRandom (a secure
random number generator). A default KeyManagerFactory and TrustManagerFactory are
used to create the KeyManager and TrustManager, respectively. The key material used is
found in the default keystore and truststore, as determined by system properties described
in Customizing the Default Keystores and Truststores, Store Types, and Store Passwords.
• The approach that gives the caller the most control over the behavior of the created
context is to call the static method [Link] on the SSLContext class, and
then initialize the context by calling the instance's proper init() method. One variant of
the init() method takes three arguments: an array of KeyManager objects, an array of
TrustManager objects, and a SecureRandom object. The KeyManager and TrustManager
objects are created by either implementing the appropriate interfaces or using the
KeyManagerFactory and TrustManagerFactory classes to generate implementations. The
KeyManagerFactory and TrustManagerFactory can then each be initialized with key
material contained in the KeyStore passed as an argument to the init() method of the
TrustManagerFactory or KeyManagerFactory classes. Finally, the getTrustManagers()
method (in TrustManagerFactory) and getKeyManagers() method (in KeyManagerFactory)
can be called to obtain the array of trust managers or key managers, one for each type of
trust or key material.
Once a TLS connection is established, an SSLSession is created which contains various
information, such as identities established and cipher suite used. The SSLSession is then used
to describe an ongoing relationship and state information between two entities. Each TLS
connection involves one session at a time, but that session may be used on many connections
between those entities, simultaneously or sequentially.
Note
An SSLContext object is automatically created, initialized, and statically assigned to
the SSLSocketFactory class when you call the [Link]()
method. Therefore, you do not have to directly create and initialize an SSLContext
object (unless you want to override the default behavior).
To create an SSLContext object by calling the getInstance() factory method, you must specify
the protocol name. You may also specify which provider you want to supply the implementation
of the requested protocol:
• public static SSLContext getInstance(String protocol);
• public static SSLContext getInstance(String protocol, String provider);
• public static SSLContext getInstance(String protocol, Provider provider);
If just a protocol name is specified, then the system will determine whether an implementation
of the requested protocol is available in the environment. If there is more than one
implementation, then it will determine whether there is a preferred one.
If both a protocol name and a provider are specified, then the system will determine whether
an implementation of the requested protocol is in the provider requested. If there is no
implementation, an exception will be thrown.
A protocol is a string (such as "TLS") that describes the secure socket protocol desired.
Common protocol names for SSLContext objects are defined in Java Security Standard
Algorithm Names.
An SSLContext can be obtained as follows:
SSLContext sc = [Link]("TLS");
If the KeyManager[] parameter is null, then an empty KeyManager will be defined for this
context. If the TrustManager[] parameter is null, then the installed security providers will be
searched for the highest-priority implementation of the TrustManagerFactory class (see
TrustManagerFactory Class), from which an appropriate TrustManager will be obtained.
Likewise, the SecureRandom parameter may be null, in which case a default implementation will
be used.
If the internal default context is used, (for example, an SSLContext is created by
[Link]() or [Link]()), then a default
KeyManager and TrustManager are created. The default SecureRandom implementation is also
chosen.
TrustManager Interface
The primary responsibility of the TrustManager is to determine whether the presented
authentication credentials should be trusted. If the credentials are not trusted, then the
connection will be terminated. To authenticate the remote identity of a secure socket peer, you
must initialize an SSLContext object with one or more TrustManager objects. You must pass
one TrustManager for each authentication mechanism that is supported. If null is passed into
the SSLContext initialization, then a trust manager will be created for you. Typically, a single
trust manager supports authentication based on X.509 public key certificates (for example,
X509TrustManager). Some secure socket implementations may also support authentication
based on shared secret keys, Kerberos, or other mechanisms.
TrustManager objects are created either by a TrustManagerFactory, or by providing a
concrete implementation of the interface.
TrustManagerFactory Class
The [Link] is an engine class for a provider-based service that
acts as a factory for one or more types of TrustManager objects. Because it is provider-based,
additional factories can be implemented and configured to provide additional or alternative trust
managers that provide more sophisticated services or that implement installation-specific
authentication policies.
Creating a TrustManagerFactory
You create an instance of this class in a similar manner to SSLContext, except for passing an
algorithm name string instead of a protocol name to the getInstance() method:
The preceding call creates an instance of the SunJSSE provider's PKIX trust manager factory.
This factory can be used to create trust managers that provide X.509 PKIX-based certification
path validity checking.
When initializing an SSLContext, you can use trust managers created from a trust manager
factory, or you can write your own trust manager, for example, using the CertPath API. See
Java PKI Programmer’s Guide. You do not need to use a trust manager factory if you
implement a trust manager using the X509TrustManager interface.
A newly created factory should be initialized by calling one of the init() methods:
Call whichever init() method is appropriate for the TrustManagerFactory you are using. If
you are not sure, then ask the provider vendor.
For many factories, such as the SunX509 TrustManagerFactory from the SunJSSE provider,
the KeyStore is the only information required to initialize the TrustManagerFactory and thus
the first init method is the appropriate one to call. The TrustManagerFactory will query the
KeyStore for information about which remote certificates should be trusted during authorization
checks.
Sometimes, initialization parameters other than a KeyStore are needed by a provider. Users of
that provider are expected to pass an implementation of the appropriate
ManagerFactoryParameters as defined by the provider. The provider can then call the
specified methods in the ManagerFactoryParameters implementation to obtain the needed
information.
For example, suppose the TrustManagerFactory provider requires initialization parameters B,
R, and S from any application that wants to use that provider. Like all providers that require
initialization parameters other than a KeyStore, the provider requires the application to provide
an instance of a class that implements a particular ManagerFactoryParameters subinterface. In
the example, suppose that the provider requires the calling application to implement and create
an instance of MyTrustManagerFactoryParams and pass it to the second init() method. The
following example illustrates what MyTrustManagerFactoryParams can look like:
Some trust managers can make trust decisions without being explicitly initialized with a
KeyStore object or any other parameters. For example, they may access trust material from a
local directory service via LDAP, use a remote online certificate status checking server, or
access default trust material from a standard local location.
// Use factory
SSLContext ctx = [Link]("TLS");
[Link](null, [Link](), null);
}
The PKIX trust manager factory uses the CertPath PKIX implementation (see PKI
Programmer's Guide Overview) from an installed security provider. The trust manager factory
can be initialized using the normal init(KeyStores) method, or by passing CertPath
parameters to the PKIX trust manager using the CertPathTrustManagerParameters
class.
Example 8-11 illustrates how to get the trust manager to use a particular LDAP certificate store
and enable revocation checking.
If the [Link](KeyStore) method is used, then default PKIX parameters
are used with the exception that revocation checking is disabled. It can be enabled by setting
the [Link] system property to true. This setting requires that the
CertPath implementation can locate revocation information by itself. The PKIX implementation
in the provider can do this in many cases but requires that the system property
[Link] be set to true. Note that the
[Link](ManagerFactoryParameters) method has revocation
checking enabled by default.
See PKIX Classes and The CertPath Class.
Example 8-11 Sample Code for Using a LDAP Certificate to Enable Revocation
Checking
The following example illustrates how to get the trust manager to use a particular LDAP
certificate store and enable revocation checking:
import [Link].*;
import [Link].*;
import [Link];
import [Link];
...
CertPathTrustManagerParameters(pkixParams);
// Use factory
SSLContext ctx = [Link]("TLS");
[Link](null, [Link](), null);
X509TrustManager Interface
The [Link].X509TrustManager interface extends the general TrustManager interface.
It must be implemented by a trust manager when using X.509-based authentication.
To support X.509 authentication of remote socket peers through JSSE, an instance of this
interface must be passed to the init method of an SSLContext object.
Creating an X509TrustManager
You can either implement this interface directly yourself or obtain one from a provider-based
TrustManagerFactory (such as that supplied by the SunJSSE provider). You could also
implement your own interface that delegates to a factory-generated trust manager. For
example, you might do this to filter the resulting trust decisions and query an end-user through
a graphical user interface.
If a null KeyStore parameter is passed to the SunJSSE PKIX or SunX509
TrustManagerFactory, then the factory uses the following process to try to find trust material:
Example 8-12 illustrates a MyX509TrustManager class that enhances the default SunJSSE
X509TrustManager behavior by providing alternative authentication logic when the default
X509TrustManager fails.
Once you have created such a trust manager, assign it to an SSLContext via the init()
method, as in the following example. Future SocketFactories created from this SSLContext
will use your new TrustManager when making trust decisions.
/*
* The default PKIX X509TrustManager9. Decisions are delegated
* to it, and a fall back to the logic in this class is performed
* if the default X509TrustManager does not trust it.
*/
X509TrustManager pkixTrustManager;
KeyStore ks = [Link]("JKS");
[Link](new FileInputStream("trustedCerts"),
"passphrase".toCharArray());
/*
* Iterate over the returned trust managers, looking
* for an instance of X509TrustManager. If found,
* use that as the default trust manager.
*/
for (int i = 0; i < [Link]; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else the
* constructor fails.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
[Link](chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
[Link](chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return [Link]();
}
}
X509ExtendedTrustManager Class
The X509ExtendedTrustManager class is an abstract implementation of the X509TrustManager
interface. It adds methods for connection-sensitive trust management. In addition, it enables
endpoint verification at the TLS layer.
In TLS 1.2 and later, both client and server can specify which hash and signature algorithms
they will accept. To authenticate the remote side, authentication decisions must be based on
both X509 certificates and the local accepted hash and signature algorithms. The local
accepted hash and signature algorithms can be obtained using the
[Link]() method.
Besides TLS 1.2 and later support, the X509ExtendedTrustManager class also supports
algorithm constraints and SSL layer host name verification. For JSSE providers and trust
manager implementations, the X509ExtendedTrustManager class is highly recommended over
the legacy X509TrustManager interface.
Creating an X509ExtendedTrustManager
You can either create an X509ExtendedTrustManager subclass yourself (which is outlined in
the following section) or obtain one from a provider-based TrustManagerFactory (such as that
supplied by the SunJSSE provider). In Java SE 7, the PKIX or SunX509 TrustManagerFactory
returns an X509ExtendedTrustManager instance.
Example 8-13 illustrates how to create a class that uses the PKIX TrustManagerFactory to
locate a default X509ExtendedTrustManager that will be used to make decisions about trust.
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;
/*
X509ExtendedTrustManager pkixTrustManager;
KeyStore ks = [Link]("JKS");
[Link](new FileInputStream("trustedCerts"), "passphrase".toCharArray());
/*
* Iterate over the returned trust managers, looking
* for an instance of X509ExtendedTrustManager. If found,
* use that as the default trust manager.
*/
for (int i = 0; i < [Link]; i++) {
if (tms[i] instanceof X509ExtendedTrustManager) {
pkixTrustManager = (X509ExtendedTrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
[Link](chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
[Link](chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Connection-sensitive verification.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType,
Socket socket)
throws CertificateException {
try {
[Link](chain, authType, socket);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return [Link]();
}
}
KeyManager Interface
The primary responsibility of the KeyManager is to select the authentication credentials that will
eventually be sent to the remote host. To authenticate yourself (a local secure socket peer) to a
remote peer, you must initialize an SSLContext object with one or more KeyManager objects.
You must pass one KeyManager for each different authentication mechanism that will be
supported. If null is passed into the SSLContext initialization, then an empty KeyManager will be
created. If the internal default context is used (for example, an SSLContext created by
[Link]() or [Link]()), then a default
KeyManager is created. See Customizing the Default Keystores and Truststores, Store Types,
and Store Passwords. Typically, a single key manager supports authentication based on X.509
public key certificates. Some secure socket implementations may also support authentication
based on shared secret keys, Kerberos, or other mechanisms.
KeyManager objects are created either by a KeyManagerFactory, or by providing a concrete
implementation of the interface.
KeyManagerFactory Class
The [Link] class is an engine class for a provider-based service
that acts as a factory for one or more types of KeyManager objects. The SunJSSE provider
implements a factory that can return a basic X.509 key manager. Because it is provider-based,
additional factories can be implemented and configured to provide additional or alternative key
managers.
Creating a KeyManagerFactory
You create an instance of this class in a similar manner to SSLContext, except for passing an
algorithm name string instead of a protocol name to the getInstance() method:
The preceding call creates an instance of the SunJSSE provider's default key manager factory,
which provides basic X.509-based authentication keys.
A newly created factory should be initialized by calling one of the init methods:
Call whichever init method is appropriate for the KeyManagerFactory you are using. If you are
not sure, then ask the provider vendor.
For many factories, such as the default SunX509 KeyManagerFactory from the SunJSSE
provider, the KeyStore and password are the only information required to initialize the
KeyManagerFactory and thus the first init method is the appropriate one to call. The
KeyManagerFactory will query the KeyStore for information about which private key and
matching public key certificates should be used for authenticating to a remote socket peer. The
password parameter specifies the password that will be used with the methods for accessing
keys from the KeyStore. All keys in the KeyStore must be protected by the same password.
Sometimes initialization parameters other than a KeyStore and password are needed by a
provider. Users of that provider are expected to pass an implementation of the appropriate
ManagerFactoryParameters as defined by the provider. The provider can then call the
specified methods in the ManagerFactoryParameters implementation to obtain the needed
information.
Some factories can provide access to authentication material without being initialized with a
KeyStore object or any other parameters. For example, they may access key material as part
of a login mechanism such as one based on JAAS, the Java Authentication and Authorization
Service.
As previously indicated, the SunJSSE provider supports a SunX509 factory that must be
initialized with a KeyStore parameter.
X509KeyManager Interface
The [Link].X509KeyManager interface extends the general KeyManager interface. It
must be implemented by a key manager for X.509-based authentication. To support X.509
authentication to remote socket peers through JSSE, an instance of this interface must be
passed to the init() method of an SSLContext object.
Creating an X509KeyManager
You can either implement this interface directly yourself or obtain one from a provider-based
KeyManagerFactory (such as that supplied by the SunJSSE provider). You could also
implement your own interface that delegates to a factory-generated key manager. For
example, you might do this to filter the resulting keys and query an end-user through a
graphical user interface.
If the default X509KeyManager behavior is not suitable for your situation, then you can create
your own X509KeyManager in a way similar to that shown in Creating Your Own
X509TrustManager.
X509ExtendedKeyManager Class
The X509ExtendedKeyManager abstract class is an implementation of the X509KeyManager
interface that allows for connection-specific key selection. It adds two methods that select a
key alias for client or server based on the key type, allowed issuers, and current SSLEngine:
If a key manager is not an instance of the X509ExtendedKeyManager class, then it will not work
with the SSLEngine class.
For JSSE providers and key manager implementations, the X509ExtendedKeyManager class is
highly recommended over the legacy X509KeyManager interface.
In TLS 1.2 and later, both client and server can specify which hash and signature algorithms
they will accept. To pass the authentication required by the remote side, local key selection
decisions must be based on both X509 certificates and the remote accepted hash and
signature algorithms. The remote accepted hash and signature algorithms can be retrieved
using the [Link]() method.
You can create your own X509ExtendedKeyManager subclass in a way similar to that shown in
Creating Your Own X509TrustManager.
Support for the Server Name Indication (SNI) Extension on the server side enables the key
manager to check the server name and select the appropriate key accordingly. For example,
suppose there are three key entries with certificates in the keystore:
• cn=[Link]
• cn=[Link]
• cn=[Link]
If the ClientHello message requests to connect to [Link] in the SNI extension, then
the server should be able to select the certificate with subject cn=[Link].
A TrustManager determines whether the remote authentication credentials (and thus the
connection) should be trusted.
A KeyManager determines which authentication credentials to send to the remote host.
SSLParameters Class
The SSLParameters class encapsulates the following parameters that affect a SSL/TLS/DTLS
connection:
• The list of cipher suites to be accepted in a TLS/DTLS handshake
• The list of protocols to be allowed
• The endpoint identification algorithm during TLS/DTLS handshaking
• The server names and server name matchers (see Server Name Indication (SNI)
Extension)
• The cipher suite preference to be used in a TLS/DTLS handshake
You can explicitly set the server name indication with the [Link]()
method. The server name indication in client mode also affects endpoint identification. In the
implementation of X509ExtendedTrustManager, it uses the server name indication retrieved by
the [Link]() method. See Example 8-14.
SSLSessionContext Interface
The [Link] interface is a grouping of SSLSession objects
associated with a single entity. For example, it could be associated with a server or client that
participates in many sessions concurrently. The methods in this interface enable the
enumeration of all sessions in a context and allow lookup of specific sessions via their session
IDs.
SSLSessionBindingListener Interface
The [Link] interface is implemented by objects that are
notified when they are being bound or unbound from an SSLSession.
SSLSessionBindingEvent Class
The [Link] class defines the event communicated to an
SSLSessionBindingListener (see SSLSessionBindingListener Interface) when it is bound
or unbound from an SSLSession (see SSLSession and ExtendedSSLSession).
HandShakeCompletedListener Interface
The [Link] interface is an interface implemented by
any class that is notified of the completion of an SSL protocol handshake on a given SSLSocket
connection.
HandShakeCompletedEvent Class
The [Link] class defines the event communicated to a
HandShakeCompletedListener (see HandShakeCompletedListener Interface) upon
completion of an SSL protocol handshake on a given SSLSocket connection.
HostnameVerifier Interface
If the SSL/TLS implementation's standard host name verification logic fails, then the
implementation calls the verify() method of the class that implements this interface and is
assigned to this HttpsURLConnection instance. If the callback class can determine that the
host name is acceptable given the parameters, it reports that the connection should be
allowed. An unacceptable response causes the connection to be terminated. See
Example 8-15.
See HttpsURLConnection for more information about how to assign the HostnameVerifier to
the HttpsURLConnection.
}
}
}
//...deleted...
X509Certificate Class
Many secure socket protocols perform authentication using public key certificates, also called
X.509 certificates. This is the default authentication mechanism for the TLS protocol.
The [Link].X509Certificate abstract class provides a standard way to access
the attributes of X.509 certificates.
Note
The [Link].X509Certificate class is supported only for backward
compatibility with previous (1.0.x and 1.1.x) versions of JSSE. New applications
should use the [Link].X509Certificate class instead.
AlgorithmConstraints Interface
The [Link] interface is used for controlling allowed
cryptographic algorithms. AlgorithmConstraints defines three permits() methods. These
methods tell whether an algorithm name or a key is permitted for certain cryptographic
functions. Cryptographic functions are represented by a set of CryptoPrimitive, which is an
enumeration containing fields like STREAM_CIPHER, MESSAGE_DIGEST, and SIGNATURE.
Thus, an AlgorithmConstraints implementation can answer questions like: Can I use this key
with this algorithm for the purpose of a cryptographic operation?
An AlgorithmConstraints object can be associated with an SSLParameters object by using
the new setAlgorithmConstraints() method. The current AlgorithmConstraints object for
an SSLParameters object is retrieved using the getAlgorithmConstraints() method.
StandardConstants Class
The StandardConstants class is used to represent standard constants definitions in JSSE.
SNIServerName Class
An instance of the abstract SNIServerName class represents a server name in the Server Name
Indication (SNI) extension. It is instantiated using the type and encoded value of the specified
server name.
You can use the getType() and getEncoded() methods to return the server name type and a
copy of the encoded server name value, respectively. The equals() method can be used to
check if some other object is "equal" to this server name. The hashCode() method returns a
hash code value for this server name. To get a string representation of the server name
(including the server name type and encoded server name value), use the toString() method.
SNIMatcher Class
An instance of the abstract SNIMatcher class performs match operations on an SNIServerName
object. Servers can use information from the Server Name Indication (SNI) extension to decide
if a specific SSLSocket or SSLEngine should accept a connection. For example, when multiple
"virtual" or "name-based" servers are hosted on a single underlying network address, the
server application can use SNI information to determine whether this server is the exact server
that the client wants to access. Instances of this class can be used by a server to verify the
acceptable server names of a particular type, such as host names.
The SNIMatcher class is instantiated using the specified server name type on which match
operations will be performed. To match a given SNIServerName, use the matches() method. To
return the server name type of the given SNIMatcher object, use the getType() method.
SNIHostName Class
An instance of the SNIHostName class (which extends the SNIServerName class) represents a
server name of type "host_name" (see StandardConstants Class) in the Server Name
Indication (SNI) Extension. To instantiate an SNIHostName, specify the fully qualified DNS host
name of the server (as understood by the client) as a String argument. The argument is illegal
in the following cases:
• The argument is empty.
• The argument ends with a trailing period.
• The argument is not a valid Internationalized Domain Name (IDN) compliant with the RFC
3490 specification.
You can also instantiate an SNIHostName by specifying the encoded host name value as a byte
array. This method is typically used to parse the encoded name value in a requested SNI
extension. Otherwise, use the SNIHostName(String hostname) constructor. The encoded
argument is illegal in the following cases:
• The argument is empty.
• The argument ends with a trailing period.
• The argument is not a valid Internationalized Domain Name (IDN) compliant with the RFC
3490 specification.
• The argument is not encoded in UTF-8 or US-ASCII.
Note
The encoded byte array passed in as an argument is cloned to protect against
subsequent modification.
To return the host name of an SNIHostName object in US-ASCII encoding, use the
getAsciiName() method. To compare a server name to another object, use the equals()
You can create an SNIMatcher object for an SNIHostName object by passing a regular
expression representing one or more host names to match to the createSNIMatcher()
method.
Customizing JSSE
JSSE includes a standard implementation that can be customized by plugging in different
implementations or specifying the default keystore, and so on.
Table 8-2 and Table 8-3 summarize which aspects can be customized, what the defaults are,
and which mechanisms are used to provide customization.
Some of the customizations are done by setting system property or Security Property values.
Sections following the table explain how to set such property values.
Note
Many of the properties shown in this table are currently used by the JSSE
implementation, but there is no guarantee that they will continue to have the same
names and types (system or security) or even that they will exist at all in future
releases. All such properties are flagged with an asterisk (*). They are documented
here for your convenience for use with the JSSE implementation.
Table 8-2 shows items that are customized by setting the [Link] property.
See How to Specify a [Link] Property
1
The list of restricted, disabled, and legacy algorithms specified in these Security Properties may change; see the [Link]
file in your JDK installation for the latest values.
* This Security Property is currently used by the JSSE implementation, but it is not guaranteed
to be examined and used by other implementations. If it is examined by another
implementation, then that implementation should handle it in the same manner as the JSSE
implementation does. There is no guarantee the property will continue to exist or be of the
same type (system or security) in future releases.
Table 8-3 shows items that are customized by setting [Link] property. See How to
Specify a [Link] Property.
* This system property is currently used by the JSSE implementation, but it is not guaranteed
to be examined and used by other implementations. If it is examined by another
implementation, then that implementation should handle it in the same manner as the JSSE
implementation does. There is no guarantee the property will continue to exist or be of the
same type (system or security) in future releases.
[Link]("propertyName", "propertyValue");
For example, a setProperty() call corresponding to the previous example for setting the
[Link] system property to specify a truststore named
"MyCacertsFile" would be:
[Link]("[Link]", "MyCacertsFile");
java-home
See Terms and Definitions
To specify a Security Property value in the security properties file, you add a line of the
following form:
propertyName=propertyValue
For example, suppose that you want to specify a different key manager factory algorithm
name than the default SunX509. You do this by specifying the algorithm name as the value
of a Security Property named [Link]. For example, to set the
value to MyX509, add the following line to the security properties file:
[Link]=MyX509
Note
Properties in the [Link] file are typically parsed only once. If you have
modified any property in this file, restart your applications to ensure that the
changes are properly reflected.
[Link]("propertyName," "propertyValue");
For example, a call to the setProperty() method corresponding to the previous example
for specifying the key manager factory algorithm name would be:
[Link]("[Link]", "MyX509");
[Link].x509v1=[Link].MyX509CertificateImpl
Note
The actual use of enabled cipher suites is restricted by algorithm constraints.
The set of cipher suites to enable by default is determined by one of the following ways in this
order of preference:
1. Explicitly set by application
2. Specified by system property
3. Specified by JSSE provider defaults
For example, explicitly setting the default enabled cipher suites in your application overrides
settings specified in [Link] or [Link] as well
as JSSE provider defaults.
The syntax of the value of these two system properties is a comma-separated list of supported
cipher suite names. Unrecognized or unsupported cipher suite names that are specified in
these properties are ignored. See Java Security Standard Algorithms for standard JSSE cipher
suite names.
Note
These system properties are currently supported by Oracle JDK and OpenJDK. They
are not guaranteed to be supported by other JDK implementations.
Caution
These system properties can be used to configure weak cipher suites, or the
configured cipher suites may be weak in the future. It is not recommended that you
use these system properties without understanding the risks.
Note
In past JSSE releases, you had to set the [Link] system
property during JSSE installation. This step is no longer required unless you want to
obtain an instance of [Link].
[Link].n=provName|className
This declares a provider, and specifies its preference order n. The preference order is the order
in which providers are searched for requested algorithms when no specific provider is
requested. The order is 1-based; 1 is the most preferred, followed by 2, and so on.
provName is the provider's name and className is the fully qualified class name of the provider.
Standard security providers are automatically registered for you in the [Link] security
properties file.
To use another JSSE provider, add a line registering the other provider, giving it whatever
preference order you prefer.
You can have more than one JSSE provider registered at the same time. The registered
providers may include different implementations for different algorithms for different engine
classes, or they may have support for some or all of the same types of algorithms and engine
classes. When a particular engine class implementation for a particular algorithm is searched
for, if no specific provider is specified for the search, then the providers are searched in
preference order and the implementation from the first provider that supplies an
implementation for the specified algorithm is used.
See Step 8.1: Configure the Provider in Steps to Implement and Integrate a Provider.
See Step 8.1: Configure the Provider in Steps to Implement and Integrate a Provider.
Provider Configuration
Some providers may require configuration. This is done using the configure method of the
Provider class, prior to calling the addProvider method of the Security class. See
SunPKCS11 Configuration for an example. The [Link]() method is new to Java
SE 9.
for specific algorithms but are not the best performing provider for other algorithms. More
flexibility is required for configuring the ordering of provider list to achieve performance gains.
The [Link] Security Property allows specific algorithms, or
service types to be selected from a preferred set of providers before accessing the list of
registered providers. See How to Specify a [Link] Property.
The [Link] Security Property does not register the providers. The
ordered provider list must be Registering the Cryptographic Provider Statically using the
[Link].n property. Any provider that is not registered is ignored.
In this syntax:
ServiceType
The name of the service type (for example: "MessageDigest"). ServiceType is optional. If it
isn’t specified, then the algorithm applies to all service types.
Algorithm
The standard algorithm name. See Java Security Standard Algorithm Names. Algorithms can
be specified as full standard name, (AES/CBC/PKCS5Padding) or as partial (AES, AES/CBC,
AES//PKCS5Padding).
Provider
The name of the provider. Any provider that isn’t listed in the registered list is ignored. See
JDK Providers.
Entries containing errors such as parsing errors are ignored. Use the command java -
[Link]=jca to debug errors.
[Link]=AES/GCM/NoPadding:SunJCE,
[Link]-256:SUN
In this syntax:
ServiceType
MessageDigest
Algorithm
AES/GCM/NoPadding, SHA-256
Provider
SunJCE, SUN
Customizing the Default Keystores and Truststores, Store Types, and Store
Passwords
Whenever a default SSLSocketFactory or SSLServerSocketFactory is created (via a call to
[Link] or [Link]), and this default
SSLSocketFactory (or SSLServerSocketFactory) comes from the JSSE reference
implementation, a default SSLContext is associated with the socket factory. (The default socket
factory will come from the JSSE implementation.)
This default SSLContext is initialized with a default KeyManager and a default TrustManager. If
a keystore is specified by the [Link] system property and an appropriate
[Link] system property (see How to Specify a [Link]
Property), then the KeyManager created by the default SSLContext will be a KeyManager
implementation for managing the specified keystore. (The actual implementation will be as
specified in Customizing the Default Key Managers and Trust Managers.) If no such system
property is specified, then the keystore managed by the KeyManager will be a new empty
keystore.
Generally, the peer acting as the server in the handshake will need a keystore for its
KeyManager in order to obtain credentials for authentication to the client. However, if one of
the anonymous cipher suites is selected, then the server's KeyManager keystore is not
necessary. And, unless the server requires client authentication, the peer acting as the client
does not need a KeyManager keystore. Thus, in these situations it may be OK if no
[Link] system property value is defined.
Note
The JDK ships with a limited number of trusted root certificates in the java-
home/lib/security/cacerts file. As documented in keytool in Java Platform,
Standard Edition Tools Reference, it is your responsibility to maintain (that is, add and
remove) the certificates contained in this file if you use this file as a truststore.
Depending on the certificate configuration of the servers that you contact, you may
need to add additional root certificates. Obtain the needed specific root certificates
from the appropriate vendor.
Note
This section describes the current JSSE reference implementation behavior. The
system properties described in this section are not guaranteed to continue to have the
same names and types (system or security) or even to exist at all in future releases.
They are also not guaranteed to be examined and used by any other JSSE
implementations. If they are examined by an implementation, then that implementation
should handle them in the same manner as the JSSE reference implementation does,
as described herein.
This default SSLContext is initialized with a KeyManager and a TrustManager. The KeyManager
and/or TrustManager supplied to the default SSLContext will be an implementation for
managing the specified keystore or truststore, as described in the aforementioned section.
The KeyManager implementation chosen is determined by first examining the
[Link] Security Property. If such a property value is specified,
then a KeyManagerFactory implementation for the specified algorithm is searched for. The
implementation from the first provider that supplies an implementation is used. Its
getKeyManagers() method is called to determine the KeyManager to supply to the default
SSLContext. Technically, getKeyManagers() returns an array of KeyManager objects, one
KeyManager for each type of key material. If no such Security Property value is specified, then
the default value of SunX509 is used to perform the search.
Note
A KeyManagerFactory implementation for the SunX509 algorithm is supplied by the
SunJSSE provider. The KeyManager that it specifies is a
[Link].X509KeyManager implementation.
implementation from the first provider that supplies an implementation is used. Its
getTrustManagers() method is called to determine the TrustManager to supply to the default
SSLContext. Technically, getTrustManagers() returns an array of TrustManager objects, one
TrustManager for each type of trust material. If no such Security Property value is specified,
then the default value of PKIX is used to perform the search.
Note
A TrustManagerFactory implementation for the PKIX algorithm is supplied by the
SunJSSE provider. The TrustManager that it specifies is a
[Link].X509TrustManager implementation.
Note
This section describes the current JSSE reference implementation behavior. The
system properties described in this section are not guaranteed to continue to have the
same names and types (system or security) or even to exist at all in future releases.
They are also not guaranteed to be examined and used by any other JSSE
implementations. If they are examined by an implementation, then that implementation
should handle them in the same manner as the JSSE reference implementation does,
as described herein.
Security Property. For example, the following line disables the SSLv3 algorithm and all of
the TLS_*_RC4_* cipher suites:
[Link]=SSLv3, RC4
Note
The algorithm restrictions specified by these Security Properties do not apply to trust
anchors or self-signed certificates.
If you require a particular condition, you can reactivate it by either removing the associated
value in the Security Property in the [Link] file or dynamically setting the proper
Security Property before JSSE is initialized.
Note
Contact your security architect before modifying these Security Properties or enabling
a cipher suite that hasn't been enabled; this allows the use of cipher suites with
weaker protections.
Note that these Security Properties effectively create a third set of cipher suites, Disabled. The
following list describes these three sets:
• Disabled: If a cipher suite contains any components (for example, RC4) on the disabled
list (for example, RC4 is specified in the [Link] Security Property),
then that cipher suite is disabled and will not be considered for a connection handshake.
• Enabled: A list of specific cipher suites that will be considered for a connection.
• Not Enabled: A list of non-disabled cipher suites that will not be considered for a
connection. To re-enable these cipher suites, call the appropriate
setEnabledCipherSuites() or setSSLParameters() methods.
If any application attempts to reenable a cipher suite, which has been disabled by the
[Link] Security Property, through the setEnabledCipherSuites()
or setSSLParameters() methods, then JSSE allows the method call but does not allow the
use of the disabled cipher suite during handshaking.
See SunJSSE Cipher Suites for a list of currently implemented SunJSSE cipher suites for this
JDK release.
Note
• If a legacy algorithm is also restricted through the [Link]
property or the [Link] API (see the method
[Link]), then the algorithm is
completely disabled and will not be negotiated.
• If your application uses an algorithm specified in the Security Property
[Link], use an alternative algorithm as soon as possible; a
future JDK release may specify a legacy algorithm as a restricted algorithm.
Note
Unless the [Link] system property is set to legacy, the
SunJSSE implementation will first try to negotiate a common DH group using FFDHE,
which is a TLS extension defined by RFC 7919. If the SunJSSE implementation can
negotiate a group, then it will use the size defined by that group. Otherwise, it will
fallback to using a keysize as described in this section. FFDHE is enabled by default,
but you can disable it by setting the system property [Link] to false.
You can specify one of the following values for this property:
• Undefined: A DH key of size 2048 bits will be used always for non-exportable cipher suites.
This is the default value for this property.
• legacy: The JSSE Oracle provider preserves the legacy behavior (for example, using
ephemeral DH keys of sizes 512 bits and 768 bits) of JDK 7 and earlier releases.
• matched:
[Link] can be used to enable or disable the MFLN extension for TLS/
DTLS.
Once a maximum fragment length has been successfully negotiated, the TLS/DTLS client and
server can immediately begin fragmenting messages (including handshake messages) to
ensure that no fragment larger than the negotiated length is sent.
It is recommended that the packet size should not be less than 256 bytes so that small
handshake messages, such as HelloVerifyRequests, are not fragmented.
[Link]=KeyLimit { , KeyLimit }
KeyLimit
AlgorithmName
A full algorithm transformation
Length
The amount of encrypted data in a session before a KeyUpdate message is sent. This value
may be an integer value in bytes or as a power of two, for example, 2^37.
For example, the following specifies that a KeyUpdate message is sent once the algorithm
AES/GCM/NoPadding has encrypted 237 bytes:
Note that when a TLS/DTLS connection is no longer needed, the client and server applications
should each close both sides of their respective connection.
Note
If the client or server trusts more CAs such that it exceeds the size limit of the
extension (less than 2^16 bytes), then the extension is not enabled. Also, some server
implementations don't allow handshake messages to exceed 2^14 bytes. Thus, there
may be interoperability issues if [Link] is set to true
and the client trusts more CAs such that it exceeds the server implementation limit.
1 "Legacy" means the original SSL/TLS specifications (that is, not RFC 5746).
2 If renegotiations are reenabled, then they will be treated as "Legacy" by the peer that is compliant with RFC 5746,
because they do not send the proper RFC 5746 messages.
3 In SSL/TLS, renegotiations can be initiated by either side. Applications communicating with a peer that has not been
upgraded in Interoperable mode and that attempt to initiate renegotiation (via [Link]()
or [Link]()) will receive an SSLHandshakeException (IOException) and the
connection will be shut down (handshake_failure). Applications that receive a renegotiation request from a
peer that has not been upgraded will respond according to the type of connection in place:
– TLSv1 A warning alert message of type no_renegotiation(100) will be sent to the peer and the
connection will remain open. Older versions of SunJSSE will shut down the connection when a
no_renegotiation alert is received.
– SSLv3 The application will receive an SSLHandshakeException, and the connection will be closed
(handshake_failure). The no_renegotiation alert is not defined in the SSLv3 specification.
Set the mode with the the following system properties (see How to Specify a [Link]
Property):
• [Link] controls whether legacy (unsafe)
renegotiations are permitted.
• [Link] allows the peer to perform the handshake
process without requiring the proper RFC 5746 messages.
Note
The system properties [Link] and
[Link] are deprecated and might be
removed in a future JDK release.
Table 8-7 Values of the System Properties for Setting the Interoperability Mode
Caution
Do not reenable the insecure SSL/TLS renegotiation, as this would reestablish the
vulnerability that was discovered in SSL/TLS protocols.
2. Otherwise, if the subject alternative names of DNS name are present in both
certificates, then they are identical.
3. Otherwise, if the subject fields are present in both certificates, then the certificate
subjects and issuers are identical.
Unsafe server certificate change in SSL/TLS renegotiations is not allowed by default. Use the
system property [Link] to define whether unsafe server
certificate change in an SSL/TLS renegotiation should be restricted or not. The default value of
this system property is false.
Caution
Do not set the system property to true unless it is really necessary, as this would re-
establish the unsafe server certificate change vulnerability.
client’s perspective, the stapled OCSP response from the server for a certificate is missing, the
client will attempt to use client-driven OCSP or Certificate Revocation Lists (CRLs) to get
revocation information if the following are true:
• The RevocationEnabled flag is set to true through the
[Link] method.
• OCSP checking is enabled by setting the [Link] Security Property to true.
OCSP checking works in conjunction with CRLs during revocation checking. See Appendix C:
OCSP Support in Java PKI Programmer's Guide.
The OCSP response is encoded using the Distinguished Encoding Rules (DER) in a format
described by the ASN.1 found in RFC 6960.
To configure a Java client to make use of the OCSP response stapled to the certificate
returned by a server, the Java client must already be set up to connect to a server using TLS,
and the server must be set up to staple an OCSP response to the certificate it returns part of
the TLS handshake.
1. Enable OCSP stapling on the client:
If necessary, set the system property [Link] to
true.
2. Enable revocation checking. You can do this in two different ways.
• Set the system property [Link] to true. You can do this
from the command line or in the code.
Server-side Properties
Most of the properties are read at SSLContext instantiation time. This means that if you set a
property, you must obtain a new SSLContext object so that an SSLSocket or SSLEngine object
you obtain from that SSLContext object will reflect the property setting. The one exception is
the [Link] property. That property is evaluated when the
ServerHandshaker object is created (essentially at the same time that an SSLSocket or
SSLEngine object gets created).
Client-Side Settings
Footnote 1 Note that client-side OCSP fallback will occur only if the [Link] Security
Property is set to true.
Developers have some flexibility in how to handle the responses provided through OCSP
stapling. OCSP stapling makes no changes to the current methodologies involved in certificate
path checking and revocation checking. This means that it is possible to have both client and
server assert the status_request extensions, obtain OCSP responses through the
CertificateStatus message, and provide user flexibility in how to react to revocation
information, or the lack thereof.
If no PKIXBuilderParameters is provided by the caller, then revocation checking is disabled. If
the caller creates a PKIXBuilderParameters object and uses
the setRevocationEnabled method to enable revocation checking, then stapled OCSP
responses will be evaluated. This is also the case if
the [Link] property is set to true.
Note
Although system properties exist that enable and disable specific TLS extensions,
such as [Link], [Link], and
[Link], an extension won't be enabled if it's disabled through
[Link] or [Link], even
though it could be enabled though the corresponding system property.
hardware. The provider must be configured before any other JCA providers in the provider list.
For details on how to configure the Oracle PKCS#11 provider, see PKCS#11 Reference Guide.
import [Link].*;
import [Link].*;
// ...
// Create KeyManagerFactory
KeyManagerFactory factory = [Link]("NewSunX509");
// Use factory
SSLContext ctx = [Link]("TLS");
[Link]([Link](), null, null);
The following list provides examples for the behavior of the SNIMatcher when receiving various
server name indication requests in the ClientHello message:
• Matcher configured to www\\.example\\.com:
– If the requested host name is [Link], then it will be accepted and a
confirmation will be sent in the ServerHello message.
– If the requested host name is [Link], then it will be rejected with an
unrecognized_name fatal error.
– If there is no requested host name or it is empty, then the request will be accepted but
no confirmation will be sent in the ServerHello message.
• Matcher configured to www\\.invalid\\.com:
– If the requested host name is [Link], then it will be rejected with an
unrecognized_name fatal error.
– If the requested host name is [Link], then it will be accepted and a
confirmation will be sent in the ServerHello message.
– If there is no requested host name or it is empty, then the request will be accepted but
no confirmation will be sent in the ServerHello message.
• Matcher is not configured:
Any requested host name will be accepted but no confirmation will be sent in the
ServerHello message.
For descriptions of new classes that implement the SNI extension, see:
• StandardConstants Class
• SNIServerName Class
• SNIMatcher Class
• SNIHostName Class
For examples, see Using the Server Name Indication (SNI) Extension.
What is ALPN?
Some applications might want or need to negotiate a shared application level value before a
TLS handshake has completed. For example, HTTP/2 uses the Application Layer Protocol
Negotiation mechanism to help establish which HTTP version ("h2", "spdy/3", "http/1.1") can or
will be used on a particular TCP or UDP port. ALPN (RFC 7301) does this without adding
network round-trips between the client and the server. In the case of HTTP/2 the protocol must
be established before the connection is negotiated, as client and server need to know what
version of HTTP to use before they start communicating. Without ALPN it would not be
possible to have application protocols HTTP/1 and HTTP/2 on the same port.
The client uses the ALPN extension at the beginning of the TLS handshake to send a list of
supported application protocols to the server as part of the ClientHello. The server reads the
list of supported application protocols in the ClientHello, and determines which of the
supported protocols it prefers. It then sends a ServerHello message back to the client with the
negotiation result. The message may contain either the name of the protocol that has been
chosen or that no protocol has been chosen.
The application protocol negotiation can thus be accomplished within the TLS handshake,
without adding network round-trips, and allows the server to associate a different certificate
with each application protocol, if desired.
Unlike many other TLS extensions, this extension does not establish properties of the session,
only of the connection. That's why you'll find the negotiated values in the SSLSocket/
SSLEngine, not the SSLSession. When session resumption or session tickets are used (see
TLS Session Resumption without Server-Side State), the previously negotiated values are
irrelevant, and only the values in the new handshake messages are considered.
To run the code the property [Link] must be set to a valid root certificate.
(This can be done on the command line).
import [Link].*;
import [Link].*;
import [Link].*;
public class SSLClient {
public static void main(String[] args) throws Exception {
[Link]();
// After the handshake, get the application protocol that has been
negotiated
String ap = [Link]();
[Link]("Application Protocol client side: \"" + ap +
"\"");
// Do simple write/read
InputStream sslIS = [Link]();
OutputStream sslOS = [Link]();
[Link](280);
[Link]();
[Link]();
[Link]();
}
}
When this code is run, it sends a ClientHello message to a Java server that has set the
ALPN values one, two, and three. The code prints the following output:
It is also possible to check the results of the negotiation during handshaking. See Determining
Negotiated ALPN Value during Handshaking.
import [Link].*;
import [Link].*;
public class SSLServer {
public static void main(String[] args) throws Exception {
[Link]();
String ap = [Link]();
[Link]("Application Protocol server side: \"" + ap +
"\"");
When this code is run and a Java client sends a ClientHello with ALPN values three and
two, the output is:
It is also possible to check the results of the negotiation during handshaking. See Determining
Negotiated ALPN Value during Handshaking.
Example 8-23 Sample Code for Custom ALPN Value Negotiation on the Server
Here is the code for a Java server that uses the custom mechanism for protocol negotiation. To
run the code the property [Link] must be set to a valid certificate. (This can
be done on the command line, see Creating a Keystore to Use with JSSE).
import [Link].*;
import [Link].*;
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) [Link]();
SSLServerSocket sslServerSocket =
(SSLServerSocket) [Link](9999);
SSLSocket sslSocket = (SSLSocket) [Link]();
[Link](
(serverSocket, clientProtocols) -> {
SSLSession handshakeSession =
[Link]();
return chooseApplicationProtocol(
serverSocket,
clientProtocols,
[Link](),
[Link]());
});
[Link]();
// After the handshake, get the application protocol that has been
// returned from the callback method.
String ap = [Link]();
[Link]("Application Protocol server side: \"" + ap +
"\"");
[Link]();
[Link](85);
[Link]();
[Link]();
}
// The callback method. Note how the parameters match the call within
// the setHandshakeApplicationProtocolSelector method.
If the cipher suite matches the one you specify in the condition statement when this code is
run , then the value three will be returned. Otherwise an empty string will be returned.
Note that the BiFunction object’s return value is a String, which will be the application
protocol name, or null to indicate that none of the advertised names are acceptable. If the
return value is an empty String then application protocol indications will not be used. If the
return value is null (no value chosen) or is a value that was not advertised by the peer, the
underlying protocol will determine what action to take. (For example, the server code will send
a "no_application_protocol" alert and terminate the connection.)
After handshaking completes on both client and server, you can check the result of the
negotiation by calling the getApplicationProtocol method on either the SSLSocket object or
the SSLEngine object.
There are some use cases where the selected ALPN and SNI values will affect the choices
made by a KeyManager or TrustManager. For example, an application might want to select
different certificate/private key sets depending on the attributes of the server and the chosen
ALPN/SNI/ciphersuite values.
The sample code given illustrates how to call the getHandshakeApplicationProtocol method
from within a custom X509ExtendedKeyManager that you create and register as the KeyManager
object.
Example 8-24 Sample Code for a Custom KeyManager
This example shows the entire code for a custom KeyManager that extends
X509ExtendedKeyManager. Most methods simply return the value returned from the KeyManager
class that is being wrapped by this MyX509ExtendedKeyManager class. However the
import [Link];
import [Link].*;
import [Link].*;
X509ExtendedKeyManager akm;
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return [Link](keyType, issuers);
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
return [Link](keyType, issuers, socket);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return [Link](keyType, issuers);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return [Link](alias);
}
@Override
When this code is registered as the KeyManager for a Java server and a Java client sends a
ClientHello with ALPN values, the output will be:
Example 8-25 Sample Code for Using a Custom KeyManager in a Java Server
This example shows a simple Java server that uses the default ALPN negotiation strategy and
the custom KeyManager, MyX509ExtendedKeyManager, shown in the prior code sample.
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
// Keystores
KeyStore keyKS = [Link]("PKCS12");
[Link](new FileInputStream("serverCert.p12"),
"password".toCharArray());
// Generate KeyManager
KeyManagerFactory kmf = [Link]("PKIX");
[Link](keyKS, "password".toCharArray());
KeyManager[] kms = [Link]();
SSLServerSocket sslServerSocket =
(SSLServerSocket) [Link](9999);
SSLSocket sslSocket = (SSLSocket) [Link]();
SSLParameters sslp = [Link]();
String[] serverAPs ={"one","two","three"};
[Link](serverAPs);
[Link](sslp);
[Link]();
String ap = [Link]();
[Link]("Application Protocol server side: \"" + ap +
"\"");
[Link]();
[Link]();
}
}
However, if you have Unicode data with characters that are above U+007F, then your
application must correctly encode or decode them to byte arrays before sending or receiving
them instead of relying on the SunJSSE provider to automatically encode or decode Unicode
characters. Alternatively, you can set the security property [Link] to UTF-8
to revert to the previous behavior.
To compare ALPN values with their expected values, you can convert them to byte arrays and
then compare them.
The expected ALPN values in the following example are the string http/1.1 and the UTF-8
encoded string (in hexadecimal) 0xABCD0xABCE0xABCF (which are the Meetei Mayek letters
"HUK UN I"). The example converts the ALPN value to a byte array with ISO-8859-1, converts
http/1.1 to a byte array with UTF-8, and manually specifies the byte array representation of
0xABCD0xABCE0xABCF.
// Encode the ALPN value into a byte array with the ISO-8859-1
// character encoding
if (([Link](bytes, HTTP1_1_BYTES) == 0 ) ||
[Link](bytes, HUK_UN_I_BYTES) == 0) {
// ...
}
Alternatively, you can compare ALPN values with the method [Link]() if you know
that the ALPN value was encoded from a String using a certain character set, for example
UTF-8. You must decode the ALPN value to a Unicode String before comparing it.
expected by the peer. For example, if the peer expects ALPN values in UTF-8, you must
convert it to a byte array with UTF-8 and then store it as a byte-oriented String:
At the beginning of the TLS handshake, the client sends a list of ALPN values to the server,
and the server selects which values it can use and ignores those that it doesn't recognize.
However, a flawed TLS implementation might instead reject unrecognized ALPN values, which
may prevent the handshake from proceeding, but developers or administrators may not notice
this flaw because it will still enable clients and servers whose ALPN values it recognizes to
connect.
Consequently, the TLS specification has introduced Generate Random Extensions And
Sustain Extensibility (GREASE) values: a reserved set of TLS protocol values that a TLS
implementation may randomly advertise to ensure that peers correctly handle unrecognized
values.
In the previous example, one of the values passed to the method
setApplicationProtocols, rfc7301Grease8A, is a GREASE value. The peer should
ignore it instead of reject it.
Troubleshooting JSSE
This section contains information for troubleshooting JSSE. First, it provides some common
Configuration Problems and ways to solve them, and then it describes helpful Debugging
Utilities.
Configuration Problems
Solutions to some common configuration problems.
...deleted...
...deleted...
Solution: Update your certificates so that they contain RSA or EC public keys.
Cause 1: This is generally caused by the remote side sending a certificate that is unknown to
the local side.
Solution 1: The best way to debug this type of problem is to turn on debugging (see
Debugging Utilities) and watch as certificates are loaded and when certificates are received via
the network connection. Most likely, the received certificate is unknown to the trust mechanism
because the wrong trust file was loaded.
Refer to the following sections:
• JSSE Classes and Interfaces
• TrustManager Interface
• KeyManager Interface
Cause 2: The system clock is not set correctly. In this case, the perceived time may be outside
the validity period on one of the certificates, and unless the certificate can be replaced with a
valid one from a truststore, the system must assume that the certificate is invalid, and therefore
throw the exception.
Solution 2: Correct the system clock time.
Cause: There was a problem with SSLContext initialization, for example, due to an incorrect
password on a keystore or a corrupted keystore (a JDK vendor once shipped a keystore in an
unknown format, and that caused this type of error).
Solution: Check initialization parameters. Ensure that any keystores specified are valid and
that the passwords specified are correct. One way that you can check this is by trying to use
keytool to examine the keystores and the relevant contents. See keytool in Java Platform,
Standard Edition Tools Reference.
Runtime Exception: "No available certificate corresponding to the SSL cipher suites
which are enabled"
Problem: When trying to run a simple SSL server program, the following exception is thrown:
Cause: Various cipher suites require certain types of key material. For example, if an RSA
cipher suite is enabled, then an RSA keyEntry must be available in the keystore. If no such
key is available, then this cipher suite cannot be used. This exception is thrown if there are no
available key entries for all of the cipher suites enabled.
Solution: Create key entries for the various cipher suite types, or use an anonymous suite.
Anonymous cipher suites are inherently dangerous because they are vulnerable to MITM
(man-in-the-middle) attacks. See RFC 5246: The Transport Layer Security (TLS) Protocol,
Version 1.2.
Refer to the following sections to learn how to pass the correct keystore and certificates:
• JSSE Classes and Interfaces
• Customizing the Default Keystores and Truststores, Store Types, and Store Passwords
• The PKCS12 Keystore Format
Cause 2: By default, keyEntries created with keytool use DSA public keys. If only DSA
keyEntries exist in the keystore, then only DSA-based cipher suites can be used. By default,
Firefox and Internet Explorer send only RSA-based cipher suites. Because the intersection of
client and server cipher suite sets is empty, this exception is thrown.
Solution 2: To interact with Firefox or Internet Explorer, you should create certificates that use
RSA-based keys. To do this, specify the -keyalg RSA option when using keytool. For example:
4. If the connection fails and SSLv2Hello is not on the enabled protocol list, restore the
enable protocol list and enable SSLv2Hello. (For example, the enable protocol list should
be SSLv2Hello, TLSv1, TLSv1.1, and TLSv1.2.) Start again from step 1.
Note
A fallback to a previous version normally means security strength downgrading to a
weaker protocol. It is not suggested to use a fallback scheme unless it is really
necessary, and you clearly know that the server does not support a higher protocol
version.
Note
As part of disabling SSLv3, some servers have also disabled SSLv2Hello, which
means communications with SSLv2Hello-active clients (JDK 6u95) will fail. Starting
with JDK 7, SSLv2Hello default to disabled on clients, enabled on servers.
SunJSSE Cannot Find a JCA Provider That Supports a Required Algorithm and
Causes a NoSuchAlgorithmException
Problem: A handshake is attempted and fails when it cannot find a required algorithm.
Examples might include:
or
Cause: SunJSSE uses JCE for all its cryptographic algorithms. If the SunJCE provider has
been deregistered from the Provider mechanism and an alternative implementation from JCE
is not available, then this exception will be thrown.
Solution: Ensure that the SunJCE is available by checking that the provider is registered with
the Provider interface. Try to run the following code in the context of your SSL connection:
import [Link].*;
Exception Thrown When Obtaining Application Resources from a Virtual Host Web
Server that Requires an SNI Extension
Problem: If you receive an Exception when trying to obtain application resources from your
web server over TLS, and your web server is implemented as a virtual host that requires a
valid Server Name Indication (SNI) extension (such as Apache HTTP Server) to distinguish the
virtual host, then the web server might not be configured correctly.
Cause: Because Java SE supports the SNI extension in the JSSE client, the requested host
name of the virtual server is included in the first message sent from the client to the server
during the TLS handshake. The server may deny the client's request for a connection if the
requested host name (the server name indication) does not match the expected server name,
which should be specified in the virtual host's configuration. This triggers an TLS handshake
unrecognized name alert, which results in an Exception being thrown.
sslContext = [Link]("DTLS");
Cause: According to DTLS Version 1.0 and DTLS Version 1.2, RC4 cipher suites must not be
used with DTLS.
Solution: Do not use RC4 based cipher suites for DTLS connections. See "JSSE Cipher Suite
Names" in Java Security Standard Algorithm Names.
Debugging Utilities
The SunJSSE provider supports dynamic debug tracing. This is similar to the mechanism that
debugs security library issues. The generic Java dynamic debug tracing support is accessed
with the [Link] system property, whereas the JSSE-specific dynamic debug
tracing support is accessed with the [Link] system property.
Note
Currently, the SunJSSE provider uses the debug utility. There is no guarantee that
other providers use the debug utility. If other providers support the debug utility, then
the implementation and output may be different. There is no guarantee the debug
utility will continue to exist or be the same (for example, have the same options or
output format) in future releases.
To view the options of the JSSE dynamic debug utility, use the following command-line option
on the java command, where MyApp is an existing Java application:
Note
• The MyApp application will not run after the debug help information is printed, as
the help code causes the application to exit.
• If you specify the value help with either dynamic debug utility when running a
program that does not use any classes that the utility was designed to debug, you
will not get the debugging options.
• To view the hexadecimal dumps of each handshake message (the colons are optional):
• To view the hexadecimal dumps of each handshake message, and to print trust manager
tracing (the commas are optional):
This section gives a brief overview of the debug output of the basic TLS 1.3 handshake. To
know more about the TLS protocol, see RFC 8446: The Transport Layer Security (TLS)
Protocol Version 1.3.
Note
• Debug output information about all possible TLS handshake combinations and
protocols is beyond the scope of this guide. Instead, refer to the relevant RFC for
more detailed information about a particular version of TLS. See TLS and DTLS
Protocols for a list of supported SSL/TLS/DTLS protocols and links to their
respective RFCs.
• The output is non-standard and may change from release to release.
This example uses the default JSSE X509KeyManager and X509TrustManager, which also
prints debug information about the keys and trusted certificates used during a connection. It
uses the ClassFileServer and SSLSocketClientWithClientAuth sample applications from
JSSE Sample Code in the Java SE 8 documentation. ClassFileServer is a simple HTTPS
server that can require client authentication. SSLSocketClientWithClientAuth demonstrates
how to use the SSLSocket class as a client to send an HTTP request and get a response
from an HTTPS server. To make things simpler, both ClassFileServer and
SSLSocketClientWithClientAuth are run from the same host.
java \
-[Link]=/my_home_directory/jssesamples/samples/
samplecacerts \
-[Link]=changeit \
ClassFileServer 2002 \
/my_home_directory/jssesamples/samples/ \
TLS true
'null'
...
The values of these system properties are null, so the default enabled cipher suites are those
that the SunJSSE provider enables by default; see The SunJSSE Provider in JDK Providers
Documentation.
The value of [Link] is checked to determine the limit of the amount of data an
algorithm may encrypt with a specific set of keys; see Limiting Amount of Data Algorithms May
Encrypt with a Set of Keys.
Initialize X509KeyManager
The X509KeyManager is initialized. It discovers that there is one keyEntry in the supplied
KeyStore for a subject called "duke". If this application wants to authenticate itself, then the
X509KeyManager searches its list of keyEntries for an appropriate credential.
Initialize a TrustManager
A TrustManager is initialized and it finds in the truststore several certificates from various
Certificate Authorities (CAs). It also finds a self-signed certificate with a distinguished name
“localhost”. A server that presents valid credentials (certificates) that chain back to a trusted
certificate in the truststore will itself be trusted.
The debug output also notifies you of disabled, unsupported, or unavailable extensions and
signature algorithms:
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "64 CF 68 A1 CF AB B1 6F 43 F6 DE 1B 49 49 DE 5A 42
9A 71 DD CB 9A E3 9F 32 00 E8 87 7A 00 DA C6",
"session id" : "02 0D BE 1B A4 5F F2 E8 B6 31 9D A4 EF F3 22 84 C3
58 0B 5C C0 57 0F A5 6D 8A 83 EB DC DA B1 B6",
"cipher suites" : "[TLS_AES_128_GCM_SHA256(0x1301),
TLS_AES_256_GCM_SHA384(0x1302),
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C),
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B),
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030),
TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D),
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E),
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032),
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F),
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3),
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F),
TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C),
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D),
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031),
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E),
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2),
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024),
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028),
TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D),
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026),
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A),
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B),
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A),
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A),
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014),
TLS_RSA_WITH_AES_256_CBC_SHA(0x0035),
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005),
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F),
TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039),
TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038),
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023),
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027),
TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C),
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025),
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029),
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067),
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040),
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009),
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013),
TLS_RSA_WITH_AES_128_CBC_SHA(0x002F),
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004),
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E),
TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033),
TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032),
TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
"compression methods" : "00",
"extensions" : [
"status_request (5)": {
"certificate status type": ocsp
"OCSP status request": {
"responder_id": <empty>
"request extensions": {
<empty>
}
}
},
"supported_groups (10)": {
"versions": [secp256r1, secp384r1, secp521r1, sect283k1, sect283r1,
sect409k1, sect409r1, sect571k1, sect571r1, secp256k1, ffdhe2048, ffdhe3072,
ffdhe4096, ffdhe6144, ffdhe8192]
},
"ec_point_formats (11)": {
"formats": [uncompressed]
},
"signature_algorithms (13)": {
"signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,
ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384,
rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384,
rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,
dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
},
"signature_algorithms_cert (50)": {
"signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,
ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384,
rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384,
rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,
dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
},
"status_request_v2 (17)": {
"cert status request": {
"certificate status type": ocsp_multi
"OCSP status request": {
"responder_id": <empty>
"request extensions": {
<empty>
}
}
}
},
"extended_master_secret (23)": {
<empty>
},
"supported_versions (43)": {
"versions": [TLSv1.3, TLSv1.2, TLSv1.1, TLSv1]
},
"psk_key_exchange_modes (45)": {
"ke_modes": [psk_dhe_ke]
},
"key_share (51)": {
"client_shares": [
{
"named group": secp256r1
"key_exchange": {
0000: 04 1F 80 50 D9 C6 03 45 7B 59 0F A7 B6 9E AE
39 ...P...E.Y.....9
0010: 37 BE B0 5B 09 D8 91 37 72 5D 2B 8E 01 0A 84 56 7..
[...7r]+....V
0020: 99 0D 37 49 8F 92 61 A9 D6 54 E1 3B EE D1 E8
D2 ..7I..a..T.;....
0030: 92 22 F9 17 CE A7 F8 51 47 C9 1E 5C D6 59 0F
4F .".....QG..\.Y.O
0040: 55
}
},
]
}
]
}
)
...
Then, the debug output shows the raw data read from the input device (InputStream) before
any processing has been performed:
Whenever the client sends or reads a message, the debug output shows the raw data sent or
read and how any messages (and their extensions) have been processed. The following
sections omit these parts of the debug output.
"signature_algorithms_cert (50)": {
"signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,
ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384,
rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384,
rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,
dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
}
]
}
)
...
"verify data": {
0000: CA 7B 74 A6 79 36 ED 62 A7 0E 14 9D 9F D0 4A 0F ..t.y6.b......J.
0010: 02 4C 78 BB E2 89 A2 C6 E8 BD 28 CA E7 D9 DB 68 .Lx.......(....h
}'}
)
...
0000: 91 C2 F7 5D 8D 90 B4 82 E4 BA C6 23 08 E2 B4 DD ...].......#....
0010: 8D 95 8F 9F 31 4F 26 F3 97 3B FB 5B 10 4D AE F6 ....1O&..;.[.M..
0020: 71 78 FB 7B 3A 4F F6 1B BF D2 E3 FB BE 53 F6 70 qx..:O.......S.p
0030: 7E 73 83 F4 9A 5E 08 19 63 C1 97 4C 10 B1 C7 3F .s...^..c..L...?
0040: 4A 7D EF 4A 30 44 15 9F D0 F2 8B C4 D1 45 69 B1 J..J0D.......Ei.
0050: D9 DB 45 83 C4 11 91 B3 81 5E 69 F4 5C 2A CF 69 ..E......^i.\*.i
0060: D3 A6 7E 75 B4 C9 30 FB 5B AC BA 9F A3 C5 0C FD ...u..0.[.......
0070: 9A 62 A4 DA 5A 80 6B 72 CD F5 A5 53 AD 14 74 1C .b..[Link]...S..t.
}
}
)
The client and server have verified the Finished messages that they have received from their
peers. Both sides may now send and receive application data over the connection.
A duplicate SSLSession is created with the newly generated PSK information attached.
0010: 0A 43 6F 6E 74 65 6E 74 2D 4C 65 6E 67 74 68 3A .Content-Length:
0020: 20 32 35 37 37 0D 0A 43 6F 6E 74 65 6E 74 2D 54 2577..Content-T
0030: 79 70 65 3A 20 74 65 78 74 2F 68 74 6D 6C 0D 0A ype: text/html..
0040: 0D 0A ..
)
...
[Link]|DEBUG|01|main|2018-08-18 01:04:48.626 EDT|
[Link]|READ: TLSv1.2 application_data, length = 2610
[Link]|DEBUG|01|main|2018-08-18 01:04:48.628 EDT|
[Link]|Raw read (
0000: 69 8D F9 A3 E9 25 09 87 F0 E0 A1 63 12 9D 81 DF i....%.....c....
0010: 42 FC FA 7A 03 74 FD D5 ED 47 6C 5F 61 F2 BB 39 B..z.t...Gl_a..9
0020: CF 64 0B B2 10 14 24 99 A3 66 8B D2 13 C9 66 FD .d....$..f....f.
...
[Link]|DEBUG|01|main|2018-08-18 01:04:48.642 EDT|
[Link]|READ: TLSv1.2 application_data, length = 2610
[Link]|DEBUG|01|main|2018-08-18 01:04:48.647 EDT|[Link]|
Plaintext after DECRYPTION (
0000: 3C 21 44 4F 43 54 59 50 45 20 68 74 6D 6C 20 50 <!DOCTYPE html P
0010: 55 42 4C 49 43 20 22 2D 2F 2F 57 33 43 2F 2F 44 UBLIC "-//W3C//D
0020: 54 44 20 58 48 54 4D 4C 20 31 2E 30 20 54 72 61 TD XHTML 1.0 Tra
0030: 6E 73 69 74 69 6F 6E 61 6C 2F 2F 45 4E 22 0A 20 nsitional//EN".
...
Code Examples
The following code examples are included in this section:
Topics
• Converting an Unsecure Socket to a Secure Socket
• Running the JSSE Sample Code
• Creating a Keystore to Use with JSSE
• Using the Server Name Indication (SNI) Extension
In a Java program that acts as a server and communicates with a client using sockets, the
socket communication is set up with code similar to the following:
import [Link].*;
import [Link].*;
. . .
ServerSocket s;
try {
s = new ServerSocket(port);
Socket c = [Link]();
The client code to set up communication with a server using sockets is similar to the following:
import [Link].*;
import [Link].*;
. . .
try {
s = new Socket(host, port);
In a Java program that acts as a server and communicates with a client using secure sockets,
the socket communication is set up with code similar to the following. Differences between this
program and the one for communication using unsecure sockets are highlighted in bold.
import [Link].*;
import [Link].*;
. . .
SSLServerSocket s;
try {
SSLServerSocketFactory sslSrvFact =
(SSLServerSocketFactory)[Link]();
s = (SSLServerSocket)[Link](port);
SSLSocket c = (SSLSocket)[Link]();
catch (IOException e) {
}
The client code to set up communication with a server using secure sockets is similar to the
following, where differences with the unsecure version are highlighted in bold:
import [Link].*;
import [Link].*;
. . .
try {
SSLSocketFactory sslFact =
(SSLSocketFactory)[Link]();
SSLSocket s = (SSLSocket)[Link](host, port);
catch (IOException e) {
}
Note
When you use the sample code, be aware that the sample programs are designed to
illustrate how to use JSSE. They are not designed to be robust applications.
Setting up secure communications involves complex algorithms. The sample
programs provide no feedback during the setup process. When you run the programs,
be patient: you may not see any output for a while. If you run the programs with the
[Link] system property set to all, you will see more feedback. For an
introduction to reading this debug information, see Debugging TLS Connections.
Note
These are very simple certificates and are not appropriate for a production
environment, but they should be sufficient for running the samples here.
The password for these keystores is: passphrase
• samplecacerts
This truststore file is very similar to the stock JDK cacerts file, in that it contains trust
certificates from several vendors. It also contains the trusted certificates from Duke and
localhost.
The password for this keystore is the same as the JDK cacert's initial password:
changeit
Please see your provider's documentation for how to configure the location of your trusted
certificate file.
Note
Users of the JDK can specify the location of the truststore by using one of the
following methods:
1. System properties:
java -[Link]=samplecacerts \
-[Link]=changeit Application
<java-home>/lib/security/jssecacerts
<java-home>/lib/security/cacerts
If you choose (2) or (3), be sure to replace this file with a production cacerts file before
deployment.
The utility keytool can be used to generate alternate certificates and keystore files.
Note
Ensure that you verify your cacerts file. Since you trust the CAs in the cacerts file
as entities for signing and issuing certificates to other entities, you must manage the
cacerts file carefully. The cacerts file should contain only certificates of the entities
and CAs you trust. It is your responsibility to verify the trusted root CA certificates
bundled in the cacerts file and make your own trust decisions. To remove an
untrusted CA certificate from the cacerts file, use the -delete command of the
keytool utility with the -cacerts option. Contact your system administrator if you do
not have permission to edit this file.
Alternatively, you can use your own truststore and keystore files. See Creating a Keystore to
Use with JSSE.
Sample Code Illustrating a Secure Socket Connection Between a Client and a Server
The sample programs in the samples/sockets directory illustrate how to set up a secure
socket connection between a client and a server.
When running the sample client programs, you can communicate with an existing server, such
as a web server, or you can communicate with the sample server program, ClassFileServer.
You can run the sample client and the sample server programs on different machines
connected to the same network, or you can run them both on one machine but from different
terminal windows.
All the sample SSLSocketClient* programs in the samples/sockets/client directory (and
URLReader* programs described in Sample Code Illustrating HTTPS Connections) can be run
with the ClassFileServer sample server program. An example of how to do this is shown in
Running SSLSocketClientWithClientAuth with ClassFileServer. You can make similar changes
to run URLReader, SSLSocketClient, or SSLSocketClientWithTunneling with
ClassFileServer.
If an authentication error occurs during communication between the client and the server
(whether using a web server or ClassFileServer), it is most likely because the necessary keys
are not in the truststore (trust key database). See Terms and Definitions. For example, the
ClassFileServer uses a keystore called testkeys containing the private key for localhost as
needed during the SSL handshake. The testkeys keystore is included in the same samples/
sockets/server directory as the ClassFileServer source. If the client cannot find a
certificate for the corresponding public key of localhost in the truststore it consults, then an
authentication error will occur. Be sure to use the samplecacerts truststore (which contains the
public key and certificate of the localhost), as described in the next section.
Configuration Requirements
When running the sample programs that create a secure socket connection between a client
and a server, you will need to make the appropriate certificates file (truststore) available. For
both the client and the server programs, you should use the certificates file samplecacerts
from the samples directory. Using this certificates file will allow the client to authenticate the
server. The file contains all the common Certificate Authority (CA) certificates shipped with the
JDK (in the cacerts file), plus a certificate for localhost needed by the client to authenticate
localhost when communicating with the sample server ClassFileServer. The
ClassFileServer uses a keystore containing the private key for localhost that corresponds to
the public key in samplecacerts.
To make the samplecacerts file available to both the client and the server, you can either copy
it to the file <java-home>/lib/security/jssecacerts, rename it to cacerts, and use it to
replace the <java-home>/lib/security/cacerts file, or add the following option to the
command line when running the java command for both the client and the server:
-[Link]=path_to_samplecacerts_file
The password for the samplecacerts truststore is changeit. You can substitute your own
certificates in the samples by using the keytool utility.
If you use a browser, such as Mozilla Firefox or Microsoft Internet Explorer, to access the
sample SSL server provided in the ClassFileServer example, then a dialog box may pop up
with the message that it does not recognize the certificate. This is normal because the
certificate used with the sample programs is self-signed and is for testing only. You can accept
the certificate for the current session. After testing the SSL server, you should exit the browser,
which deletes the test certificate from the browser's namespace.
For client authentication, a separate duke certificate is available in the appropriate directories.
The public key and certificate is also stored in the samplecacerts file.
Running SSLSocketClient
The [Link] program in JSSE Sample Code in the Java SE 8 documentation
demonstrates how to create a client that uses an SSLSocket to send an HTTP request and to
get a response from an HTTPS server. The output of this program is the HTML source for
[Link]
You must not be behind a firewall to run this program as provided. If you run it from behind a
firewall, you will get an UnknownHostException because JSSE cannot find a path through your
firewall to [Link]. To create an equivalent client that can run from behind a firewall,
set up proxy tunneling as illustrated in the sample program SSLSocketClientWithTunneling.
Running SSLSocketClientWithTunneling
The [Link] program in JSSE Sample Code in the Java SE 8
documentation illustrates how to do proxy tunneling to access a secure web server from
behind a firewall. To run this program, you must set the following Java system properties to the
appropriate values:
java -[Link]=webproxy
-[Link]=ProxyPortNumber
SSLSocketClientWithTunneling
Note
Proxy specifications with the -D options are optional. Replace webproxy with the name
of your proxy host and ProxyPortNumber with the appropriate port number.
The program will return the HTML source file from [Link]
Running SSLSocketClientWithClientAuth
The [Link] program in JSSE Sample Code in the Java
SE 8 documentation shows how to set up a key manager to do client authentication if required
by a server. This program also assumes that the client is not outside a firewall. You can modify
the program to connect from inside a firewall by following the example in
SSLSocketClientWithTunneling.
To run this program, you must specify three parameters: host name, port number, and
requested file path. To mirror the previous examples, you can run this program without client
authentication by setting the host to [Link], the port to 443, and the requested file
path to [Link] The output when using these parameters is the HTML
for the website [Link]
Running ClassFileServer
The program referred to herein as ClassFileServer is made up of two files:
[Link] and [Link] in JSSE Sample Code in the Java SE 8
documentation.
To execute them, run [Link], which requires the following parameters:
• port can be any available unused port number, for example, you can use the number
2001.
• docroot indicates the directory on the server that contains the file you want to retrieve. For
example, on Linux, you can use /home/userid/ (where userid refers to your particular
UID), whereas on Windows, you can use c:\.
• TLS is an optional parameter that indicates that the server is to use SSL or TLS.
• true is an optional parameter that indicates that client authentication is required. This
parameter is only consulted if the TLS parameter is set.
Note
The TLS and true parameters are optional. If you omit them, indicating that an
ordinary (not TLS) file server should be used, without authentication, then nothing
happens. This is because one side (the client) is trying to negotiate with TLS, while the
other (the server) is not, so they cannot communicate.
The server expects GET requests in the form GET /path_to_file.
Note
You can modify the other SSLClient* applications' GET commands to connect to a
local machine running ClassFileServer.
A second, and often simpler, way is through the standard Java URL API. You can
communicate securely with an SSL-enabled web server by using the HTTPS URL protocol or
scheme using the [Link] class.
Support for HTTPS URL schemes is implemented in many of the common browsers, which
allows access to secured communications without requiring the socket-level API provided with
JSSE.
An example URL is [Link]
The trust and key management for the HTTPS URL implementation is environment-specific.
The JSSE implementation provides an HTTPS URL implementation. To use a different HTTPS
protocol implementation, set the [Link]. See How to Specify a
[Link] Property to the package name. See the [Link] class documentation
for details.
The samples that you can download with JSSE include two sample programs that illustrate
how to create an HTTPS connection. Both of these sample programs ([Link] and
[Link] ) are in the samples/urls directory.
Running URLReader
The [Link] program in JSSE Sample Code in the Java SE 8 documentation
illustrates using the URL class to access a secure site. The output of this program is the HTML
source for [Link] By default, the HTTPS protocol implementation
included with JSSE is used. To use a different implementation, set the system property
[Link] value to be the name of the package containing the
implementation.
If you are running the sample code behind a firewall, then you must set the [Link]
and [Link] system properties. For example, to use the proxy host "webproxy" on
port 8080, you can use the following options for the java command:
-[Link]=webproxy
-[Link]=8080
Alternatively, you can set the system properties within the source code with the
[Link] method setProperty(). For example, instead of using the command-line
options, you can include the following lines in your program:
[Link]("[Link]", "[Link]");
[Link]("[Link]", "webproxy");
[Link]("[Link]", "8080");
Running URLReaderWithOptions
The [Link] program in JSSE Sample Code in the Java SE 8
documentation is essentially the same as the [Link] program, except that it allows
you to optionally input any or all of the following system properties as arguments to the
program when you run it:
• [Link]
• [Link]
• [Link]
• [Link]
To run URLReaderWithOptions, enter the following command:
Note
Multiple protocol handlers can be included in the protocolhandlerpkgs argument as a
list with items separated by vertical bars. Multiple SSL cipher suite names can be
included in the ciphersarray argument as a list with items separated by commas. The
possible cipher suite names are the same as those returned by the
[Link]() method. The suite names are taken from
the SSL and TLS protocol specifications.
You need a protocolhandlerpkgs argument only if you want to use an HTTPS protocol
handler implementation other than the default one provided by Oracle.
If you are running the sample code behind a firewall, then you must include arguments for the
proxy host and the proxy port. Additionally, you can include a list of cipher suites to enable.
Here is an example of running URLReaderWithOptions and specifying the proxy host
"webproxy" on port 8080:
methods. The second demo is a more realistic example showing how SSLEngine might be
combined with Java NIO to create a rudimentary HTTP/HTTPS server.
Running SSLEngineSimpleDemo
The [Link] program in JSSE Sample Code in the Java SE 8
documentation is a very simple application that focuses on the operation of the SSLEngine
while simplifying the I/O and threading issues. This application creates two SSLEngine objects
that exchange SSL/TLS messages via common ByteBuffer objects. A single loop serially
performs all of the engine operations and demonstrates how a secure connection is
established (handshaking), how application data is transferred, and how the engine is closed.
The SSLEngineResult provides a great deal of information about the current state of the
SSLEngine. This example does not examine all of the states. It simplifies the I/O and threading
issues to the point that this is not a good example for a production environment; nonetheless, it
is useful to demonstrate the overall function of the SSLEngine.
Note
It is beyond the scope of this example to explain each step in detail. See the keytool
command in Java Platform, Standard Edition Tools Reference for more information.
2. Examine the keystore. Notice that the entry type is PrivatekeyEntry, which means that
this entry has a private key associated with it).
Extensions:
75 ...HB.h....\,k.u
0010: 5F 19 78 43 _.xC
]
]
Alternatively, you could generate a Certificate Signing Request (CSR) with the -certreq
command and send that to a Certificate Authority (CA) for signing. See the section
"Requesting a Signed Certificate from a CA" in the keytool command for an example.
4. Import the certificate into a new truststore.
Extensions:
5. Examine the truststore. Note that the entry type is trustedCertEntry, which means that a
private key is not available for this entry. It also means that this file is not suitable as a
keystore of the KeyManager.
Extensions:
SubjectKeyIdentifier [
KeyIdentifier [
0000: 7F C9 95 48 42 8D 68 91 BA 1E E6 5C 2C 6B FF
75 ...HB.h....\,k.u
0010: 5F 19 78 43 _.xC
]
]
*******************************************
*******************************************
6. Now run your applications with the appropriate keystores. Because this example assumes
that the default X509KeyManager and X509TrustManager are used, you select the keystores
using the system properties described in Customizing JSSE.
% java -[Link]=keystore -
[Link]=password Server
% java -[Link]=truststore -
[Link]=trustword Client
Note
This example authenticated the server only. For client authentication, provide a similar
keystore for the client's keys and an appropriate truststore for the server.
[Link]([Link]());
Another way is to create an SNIMatcher subclass with a matches() method that always
returns false:
@Override
public boolean matches(SNIServerName serverName) {
return false;
}
}
• Case 3. The server wants to accept connections to any host names in the [Link]
domain.
Set the recognizable server name for host_name as a pattern that includes all
*.[Link] addresses:
• Case 4. The server wants to switch a socket from client mode to server mode.
First switch the mode with the following method: [Link](false).
Then reset the server name indication parameters on the socket.
[Link] explores the initial ClientHello message from a TLS client, but it does not
initiate handshaking or consume network data. The [Link]() method parses
the ClientHello message, and retrieves the security parameters into SSLCapabilities. The
method must be called before handshaking occurs on any TLS connections.
3. Read and buffer bytes from the socket input stream, and then explore the buffered
bytes.
// Explore
capabilities = [Link](buffer, 0, recordLength);
if (capabilities != null) {
[Link]("Record version: " +
[Link]());
[Link]("Hello version: " + [Link]());
}
5. Look for the registered server name handler for this server name indication.
If the service of the host name is resident in a virtual machine or another distributed
system, then the application must forward the connection to the destination. The
application will need to read and write the raw internet data, rather then the SSL
application from the socket stream.
If the service of the host name is resident in the same process, and the host name service
can use the SSLSocket directly, then the application will need to set the SSLSocket instance
to the server:
3. Read and buffer bytes from the socket input stream, and then explore the buffered
bytes.
int n = [Link](buffer);
if (n < 0) {
throw new Exception("unexpected end of stream!");
}
5. Look for the registered server name handler for this server name indication.
If the service of the host name is resident in a virtual machine or another distributed
system, then the application must forward the connection to the destination. The
application will need to read and write the raw internet data, rather then the SSL
application from the socket stream.
If the service of the host name is resident in the same process, and the host name service
can use the SSLEngine directly, then the application will simply feed the net data to the
SSLEngine instance:
Failover SSLContext
The [Link]() method does not check the validity of TLS/DTLS contents. If the
record format does not comply with TLS/DTLS specification, or the explore() method is
invoked after handshaking has started, then the method may throw an IOException and be
unable to produce network data. In such cases, handle the exception thrown by
[Link]() by using a failover SSLContext, which is not used to negotiate a TLS/
DTLS connection, but to close the connection with the proper alert message. The following
example illustrates a failover SSLContext. You can find an example of the DenialSNIMatcher
class in Case 2 in Typical Server-Side Usage Examples.
try {
InputStream sslIS = [Link]();
[Link]();
} catch (Exception e) {
[Link]("Server exception " + e);
} finally {
[Link]();
}
Standard Names
The JDK Security API requires and uses a set of standard names for algorithms, certificates
and keystore types. See the Java Security Standard Algorithm Names specification. Find
specific provider information in JDK Providers Documentation.
Provider Pluggability
JSSE is fully pluggable and does not restrict the use of third-party JSSE providers in any way.
Topics
PKI Programmer's Guide Overview
Core Classes and Interfaces
Implementing a Service Provider
Appendix A: Standard Names
Appendix B: The CertPath Implementation in the SUN Provider
Appendix C: OCSP Support
Appendix D: CertPath Implementation in JdkLDAP Provider
Appendix E: Disabling Cryptographic Algorithms
Figure 9-1 Certification Path from CA's Public Key (CA 1) to the Target Subject
A certification path must be validated before it can be relied on to establish trust in a subject's
public key. Validation can consist of various checks on the certificates contained in the
certification path, such as verifying the signatures and checking that each certificate has not
been revoked. The PKIX standards define an algorithm for validating certification paths
consisting of X.509 certificates.
Often a user may not have a certification path from a most-trusted CA to the subject. Providing
services to build or discover certification paths is an important feature of public key enabled
systems. RFC 2587 defines an LDAP (Lightweight Directory Access Protocol) schema
definition that facilitates the discovery of X.509 certification paths using the LDAP directory
service protocol.
Building and validating certification paths is an important part of many standard security
protocols such as SSL/TLS/DTLS, S/MIME, and IPsec. The Java Certification Path API
provides a set of classes and interfaces for developers who need to integrate this functionality
into their applications. This API benefits two types of developers: those who need to write
service provider implementations for a specific certification path building or validation
algorithm; and those who need to access standard algorithms for creating, building, and
validating certification paths in an implementation-independent manner.
Public Keys
These are numbers associated with a particular entity, and are intended to be known to
everyone who needs to have trusted interactions with that entity. Public keys are used to verify
signatures.
Digitally Signed
If some data is digitally signed, it has been stored with the "identity" of an entity, and a
signature that proves that entity knows about the data. The data is rendered unforgeable by
signing with the entity's private key.
Identity
A known way of addressing an entity. In some systems the identity is the public key, in others
it can be anything from a UNIX UID to an Email address to an X.509 Distinguished Name.
Signature
A signature is computed over some data using the private key of an entity (the signer).
Private Keys
These are numbers, each of which is supposed to be known only to the particular entity whose
private key it is (that is, it's supposed to be kept secret). Private and public keys exist in pairs
in all public key cryptography systems (also referred to as "public key crypto systems"). In a
typical public key crypto system, such as DSA, a private key corresponds to exactly one public
key. Private keys are used to compute signatures.
Entity
An entity is a person, organization, program, computer, business, bank, or something else you
are trusting to some degree.
Basically, public key cryptography requires access to users' public keys. In a large-scale
networked environment it is impossible to guarantee that prior relationships between
communicating entities have been established or that a trusted repository exists with all used
public keys. Certificates were invented as a solution to this public key distribution problem.
Now a Certification Authority (CA) can act as a Trusted Third Party. CAs are entities (for
example, businesses) that are trusted to sign (issue) certificates for other entities. It is
assumed that CAs will only create valid and reliable certificates as they are bound by legal
agreements. There are many public Certification Authorities, such as Comodo, DigiCert, and
GoDaddy.
Version
This identifies which version of the X.509 standard applies to this certificate, which affects
what information can be specified in it. Thus far, three versions are defined.
Serial Number
The entity that created the certificate is responsible for assigning it a serial number to
distinguish it from other certificates it issues. This information is used in numerous ways, for
example when a certificate is revoked its serial number is placed in a Certificate Revocation
List (CRL).
Issuer Name
The X.500 name of the entity that signed the certificate. This is normally a CA. Using this
certificate implies trusting the entity that signed this certificate. (Note that in some cases, such
as root or top-level CA certificates, the issuer signs its own certificate.)
Validity Period
Each certificate is valid only for a limited amount of time. This period is described by a start
date and time and an end date and time, and can be as short as a few seconds or almost as
long as a century. The validity period chosen depends on a number of factors, such as the
strength of the private key used to sign the certificate or the amount one is willing to pay for a
certificate. This is the expected period that entities can rely on the public value, if the
associated private key has not been compromised.
Subject Name
The name of the entity whose public key the certificate identifies. This name uses the X.500
standard, so it is intended to be unique across the Internet. This is the Distinguished Name
(DN) of the entity, for example,
(These refer to the subject's Common Name, Organizational Unit, Organization, and Country.)
X.509 Version 1 has been available since 1988, is widely deployed, and is the most generic.
X.509 Version 2 introduced the concept of subject and issuer unique identifiers to handle the
possibility of reuse of subject and/or issuer names over time. Most certificate profile documents
strongly recommend that names not be reused, and that certificates should not make use of
unique identifiers. Version 2 certificates are not widely used.
X.509 Version 3 is the most recent (1996) and supports the notion of extensions, whereby
anyone can define an extension and include it in the certificate. Some common extensions in
use today are: KeyUsage (limits the use of the keys to particular purposes such as "signing-
only") and AlternativeNames (allows other identities to also be associated with this public key,
for example, DNS names, Email addresses, IP addresses). Extensions can be marked critical
to indicate that the extension should be checked and enforced/used. For example, if a
certificate has the KeyUsage extension marked critical and set to "keyCertSign" then if this
certificate is presented during SSL communication, it should be rejected, as the certificate
extension indicates that the associated private key should only be used for signing certificates
and not for SSL use.
All the data in a certificate is encoded using two related standards called ASN.1/DER. Abstract
Syntax Notation 1 describes data. The Distinguished Encoding Rules describe a single way to
store and transfer that data.
What Java Tool Can Generate, Display, Import, and Export X.509 Certificates?
There is a tool named keytool that can be used to create public/private key pairs and X.509 v3
certificates, and to manage keystores. Keys and certificates are used to digitally sign your Java
applications and applets (see jarsigner).
A keystore is a protected database that holds keys and certificates. Access to a keystore is
guarded by a password (defined at the time the keystore is created, by the person who creates
the keystore, and changeable only when providing the current password). In addition, each
private key in a keystore can be guarded by its own password.
Using keytool, it is possible to display, import, and export X.509 v1, v2, and v3 certificates
stored as files, and to generate new v3 certificates. For examples, see keytool in the Java
Platform, Standard Edition Tools Reference.
The Java Certification Path API also includes a set of algorithm-specific classes modeled for
use with the PKIX certification path validation algorithm defined in RFC 5280: Public Key
Infrastructure Certificate and Certificate Revocation List (CRL) Profile. The PKIX Classes are:
• TrustAnchor
• PKIXParameters
• PKIXCertPathValidatorResult
• PKIXBuilderParameters
• PKIXCertPathBuilderResult
• PKIXCertPathChecker
• PKIXRevocationChecker
The complete reference documentation for the relevant Certification Path API classes can be
found in [Link] .
Most of the classes and interfaces in the CertPath API are not thread-safe. However, there
are some exceptions, which will be noted in this guide and in the API specification. Multiple
threads that need to access a single non-thread-safe object concurrently should synchronize
amongst themselves and provide the necessary locking. Multiple threads each manipulating
separate objects need not synchronize.
Topics
Basic Certification Path Classes
Certification Path Validation Classes
Certification Path Building Classes
Certificate/CRL Storage Classes
PKIX Classes
Topics
The CertPath Class
The CertificateFactory Class
The CertPathParameters Interface
All CertPath objects are serializable, immutable and thread-safe and share the following
characteristics:
• A type
This corresponds to the type of the certificates in the certification path, for example: X.509.
The type of a CertPath is obtained using the method:
Also, the getEncodings method returns an iterator over the supported encoding format
Strings (the default encoding format is returned first):
All CertPath objects are also Serializable. CertPath objects are resolved into an alternate
[Link] object during serialization. This allows a CertPath object to be serialized
into an equivalent representation regardless of its underlying implementation.
CertPath objects are generated from an encoded byte array or list of Certificates using a
CertificateFactory. Alternatively, a CertPathBuilder may be used to try to find a CertPath from a
most-trusted CA to a particular subject. Once a CertPath object has been created, it may be
validated by passing it to the validate method of CertPathValidator. Each of these concepts
are explained in more detail in subsequent sections.
To find out what encoding formats are supported, use the getCertPathEncodings method (the
default encoding is returned first):
To generate a certification path object from a List of Certificate objects, use the following
method:
A CertificateFactory always returns CertPath objects that consist of Certificates that are
of the same type as the factory. For example, a CertificateFactory of type X.509 returns
The following code sample illustrates generating a certification path from a PKCS#7 encoded
certificate reply stored in a file:
Here's another code sample that fetches a certificate chain from a KeyStore and converts it to
a CertPath using a CertificateFactory:
Topics
The CertPathValidator Class
The CertPathValidatorResult Interface
The algorithm parameter is the name of a certification path validation algorithm (for example,
"PKIX"). Standard CertPathValidator algorithm names are listed in the Java Security
Standard Algorithm Names.
If the validation algorithm is successful, the result is returned in an object implementing the
CertPathValidatorResult interface. Otherwise, a CertPathValidatorException is thrown. The
CertPathValidatorException contains methods that return the CertPath, and if relevant, the
index of the certificate that caused the algorithm to fail and the root exception or cause of the
failure.
Note that the CertPath and CertPathParameters passed to the validate method must be of a
type that is supported by the validation algorithm. Otherwise, an
InvalidAlgorithmParameterException is thrown. For example, a CertPathValidator
instance that implements the PKIX algorithm validates CertPath objects of type X.509 and
CertPathParameters that are an instance of PKIXParameters.
The following code sample shows how to create a CertPathValidator and use it to validate a
certification path. The sample assumes that the CertPath and CertPathParameters objects
which are passed to the validate method have been previously created; a more complete
example will be illustrated in the section describing the PKIX classes.
[Link](1);
}
Topics
The CertPathBuilder Class
The CertPathBuilderResult Interface
The algorithm parameter is the name of a certification path builder algorithm (for example,
"PKIX"). Standard CertPathBuilder algorithm names are listed in Java Security Standard
Algorithm Names.
If the build algorithm is successful, the result is returned in an object implementing the
CertPathBuilderResult interface. Otherwise, a CertPathBuilderException is thrown containing
information about the failure; for example, the underlying exception (if any) and an error
message.
Note that the CertPathParameters passed to the build method must be of a type that is
supported by the build algorithm. Otherwise, an InvalidAlgorithmParameterException is
thrown.
The purpose of the CertPathBuilderResult interface is to group (and provide type safety for)
all build results. Like the CertPathValidatorResult interface, CertPathBuilderResult
extends Cloneable and defines a clone() method that does not throw an exception. This
allows applications to clone any CertPathBuilderResult object.
Objects implementing the CertPathBuilderResult interface are returned by the build method
of CertPathBuilder.
The following code sample shows how to create a CertPathBuilder and use it to build a
certification path. The sample assumes that the CertPathParameters object which is passed to
the build method has been previously created; a more complete example will be illustrated in
the section describing the PKIX classes.
A CertPathValidator implementation may use the CertStore object that the caller specifies
as a callback mechanism to fetch CRLs for performing revocation checks. Similarly, a
CertPathBuilder may use the CertStore as a callback mechanism to fetch certificates and, if
performing revocation checks, CRLs.
Topics
The CertStore Class
The CertStoreParameters Interface
The CertSelector and CRLSelector Interfaces
The type parameter is the name of a certificate repository type (for example, "LDAP").
Standard CertStore types are listed in Java Security Standard Algorithm Names.
The initialization parameters (params) are specific to the repository type. For example, the
initialization parameters for a server-based repository may include the hostname and the port
of the server. An InvalidAlgorithmParameterException is thrown if the parameters are invalid
for this CertStore type. The getCertStoreParameters method returns the
CertStoreParameters that were used to initialize a CertStore:
Retrieving Certificates
After you have created a CertStore object, you can retrieve certificates from the repository
using the getCertificates method. This method takes a CertSelector (discussed in more detail
later) object as an argument, which specifies a set of selection criteria for determining which
certificates should be returned:
Retrieving CRLs
You can also retrieve CRLs from the repository using the getCRLs method. This method takes
a CRLSelector (discussed in more detail later) object as an argument, which specifies a set of
selection criteria for determining which CRLs should be returned:
The main purpose of this interface is to group and provide type safety for all certificate storage
parameter specifications. The CertStoreParameters interface extends the Cloneable interface
and defines a clone method that does not throw an exception. Implementations of this
interface should implement and override the [Link]() method, if necessary. This allows
applications to clone any CertStoreParameters object.
See LDAPCertStoreParameters.
See CollectionCertStoreParameters.
The CertSelector and CRLSelector interfaces each define a method named match. The match
method takes a Certificate or CRL object as an argument and returns true if the object
satisfies the selection criteria. Otherwise, it returns false. The match method for the
CertSelector interface is defined as follows:
See RFC 5280 for definitions of the X.509 certificate extensions mentioned in this section.
public X509CertSelector()
The specified distinguished name (in X500Principal, RFC 2253 String or ASN.1 DER encoded
form) must match the issuer distinguished name in the certificate. If null, any issuer
distinguished name will do. Note that use of an X500Principal to represent a distinguished
name is preferred because it is more efficient and suitably typed.
Similarly, the setSubject methods set the subject criterion:
The specified distinguished name (in X500Principal, RFC 2253 String or ASN.1 DER encoded
form) must match the subject distinguished name in the certificate. If null, any subject
distinguished name will do.
The setSerialNumber method sets the serialNumber criterion:
The specified serial number must match the certificate serial number in the certificate. If null,
any certificate serial number will do.
The certificate must contain an Authority Key Identifier extension matching the specified value.
If null, no check will be done on the authorityKeyIdentifier criterion.
The setCertificateValid method sets the certificateValid criterion:
The specified date must fall within the certificate validity period for the certificate. If null, any
date is valid.
The setKeyUsage method sets the keyUsage criterion:
The certificate's Key Usage Extension must allow the specified key usage values (those which
are set to true). If null, no keyUsage check will be done.
Here is an example of retrieving X.509 certificates from an LDAP CertStore with the
X509CertSelector class.
First, we create the LDAPCertStoreParameters object that we will use to initialize the
CertStore object with the hostname and port of the LDAP server:
Next, create the CertStore object, and pass it the LDAPCertStoreParameters object, as in the
following statement:
This call creates a CertStore object that retrieves certificates and CRLs from an LDAP
repository using the schema defined in RFC 2587.
The following block of code establishes an X509CertSelector to retrieve all unexpired (as of
the current date and time) end-entity certificates issued to a particular subject with 1) a key
usage that allows digital signatures, and 2) a subject alternative name with a specific email
address:
Then we pass the selector to the getCertificates method of our CertStore object that we
previously created:
A PKIX CertPathBuilder may use similar code to help discover and sort through potential
certificates by discarding those that do not meet validation constraints or other criteria.
public X509CRLSelector()
The issuer distinguished name in the CRL must match at least one of the specified
distinguished names. The setIssuers method is preferred as the use of X500Principals to
represent distinguished names is more efficient and suitably typed. For the setIssuerNames
method, each entry of the names argument is either a String or a byte array (representing the
name, in RFC 2253 or ASN.1 DER encoded form, respectively). If null, any issuer
distinguished name will do.
The setMinCRLNumber and setMaxCRLNumber methods set the minCRLNumber and
maxCRLNumber criterion:
The CRL must have a CRL Number extension whose value is greater than or equal to the
specified value if the setMinCRLNumber method is called, and less than or equal to the specified
value if the setMaxCRLNumber method is called. If the value passed to one of these methods is
null, the corresponding check is not done.
The setDateAndTime method sets the dateAndTime criterion:
The specified date must be equal to or later than the value of the thisUpdate component of the
CRL and earlier than the value of the nextUpdate component. If null, no dateAndTime check
will be done.
The setCertificateChecking method sets the certificate whose revocation status is being
checked:
This is not a criterion. Rather, it is optional information that may help a CertStore find CRLs
that would be relevant when checking revocation for the specified certificate. If null is specified,
then no such optional information is provided. An application should always call this method
when checking revocation for a particular certificate, as it may provide the CertStore with more
information for finding the correct CRLs and filtering out irrelevant ones.
Then we pass the selector to the getCRLs method of our CertStore object (created in the
X509CertSelector example):
PKIX Classes
The Java Certification Path API includes a set of algorithm-specific classes modeled for use
with the PKIX certification path validation algorithm.
The PKIX certification path validation algorithm is defined in RFC 5280: Internet X.509 Public
Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile.
Topics
The TrustAnchor Class
The PKIXParameters Class
The CertPathValidatorResult Interface
The PolicyNode Interface and PolicyQualifierInfo Class
All TrustAnchor objects are immutable and thread-safe. That is, multiple threads may
concurrently invoke the methods defined in this class on a single TrustAnchor object (or more
than one) with no ill effects. Requiring TrustAnchor objects to be immutable and thread-safe
allows them to be passed around to various pieces of code without worrying about coordinating
access.
Note
Although this class is described as a PKIX class it may be used with other X.509
certification path validation algorithms.
The nameConstraints parameter is specified as a byte array containing the ASN.1 DER
encoding of a NameConstraints extension. An IllegalArgumentException is thrown if the
name constraints cannot be decoded (are not formatted correctly).
Note
The getTrustedCert method returns null if the trust anchor was specified as a public
key and name pair. Likewise, the getCA, getCAName and getCAPublicKey methods
return null if the trust anchor was specified as an X509Certificate.
An X.509 CertPath object and a PKIXParameters object are passed as arguments to the
validate method of a CertPathValidator instance implementing the PKIX algorithm. The
CertPathValidator uses the parameters to initialize the PKIX certification path validation
algorithm.
The first constructor allows the caller to specify the most-trusted CAs as a Set of TrustAnchor
objects. Alternatively, a caller can use the second constructor and specify a KeyStore instance
containing trusted certificate entries, each of which will be considered as a most-trusted CA.
The setInitialPolicies method sets the initial policy identifiers, as specified by the PKIX
validation algorithm. The elements of the Set are object identifiers (OIDs) represented as a
String. If the initialPolicies parameter is null or not set, any policy is acceptable:
The setDate method sets the time for which the validity of the path should be determined. If
the date parameter is not set or is null, the current date is used:
The setPolicyMappingInhibited method sets the value of the policy mapping inhibited flag.
The default value for the flag, if not specified, is false:
The setExplicitPolicyRequired method sets the value of the explicit policy required flag. The
default value for the flag, if not specified, is false:
The setAnyPolicyInhibited method sets the value of the any policy inhibited flag. The default
value for the flag, if not specified, is false:
The setTargetCertConstraints method allows the caller to set constraints on the target or
end-entity certificate. For example, the caller can specify that the target certificate must contain
a specific subject name. The constraints are specified as a CertSelector object. If the
selector parameter is null or not set, no constraints are defined on the target certificate:
The setCertStores method allows a caller to specify a List of CertStore objects that will be
used by a PKIX implementation of CertPathValidator to find CRLs for path validation. This
provides an extensible mechanism for specifying where to locate CRLs. The setCertStores
method takes a List of CertStore objects as a parameter. The first CertStores in the list may
be preferred to those that appear later.
The setCertPathCheckers method allows a caller to extend the PKIX validation algorithm by
creating implementation-specific certification path checkers. For example, this mechanism can
The next step is to create a TrustAnchor object. This will be used as an anchor for validating the
certification path. In this example, the most-trusted CA is specified as a public key and name
(name constraints are not applied and are specified as null):
The next step is to create a PKIXParameters object. This will be used to populate the parameters
used by the PKIX algorithm. In this example, we pass to the constructor a Set containing a
single element - the TrustAnchor we created in the previous step:
Next, we populate the parameters object with constraints or other parameters used by the
validation algorithm. In this example, we enable the explicitPolicyRequired flag and specify a
set of initial policy OIDs (the contents of the set are not shown):
The final step is to validate the certification path using the input parameter set we have
created:
try {
PKIXCertPathValidatorResult result =
If the validation algorithm is successful, the policy tree and subject public key resulting from the
validation algorithm are obtained using the getPolicyTree and getPublicKey methods of
PKIXCertPathValidatorResult.
Otherwise, a CertPathValidatorException is thrown and the caller can catch the exception
and print some details about the failure, such as the error message and the index of the
certificate that caused the failure.
This class (which extends the PKIXParameters class) specifies the set of parameters to be used
with CertPathBuilder class that build certification paths validated against the PKIX certification
path validation algorithm.
A PKIXBuilderParameters object is passed as an argument to the build method of a
CertPathBuilder instance implementing the PKIX algorithm. All PKIX CertPathBuilders must
return certification paths which have been validated according to the PKIX certification path
validation algorithm.
Please note that the mechanism that a PKIX CertPathBuilder uses to validate a constructed
path is an implementation detail. For example, an implementation might attempt to first build a
path with minimal validation and then fully validate it using an instance of a PKIX
CertPathValidator, whereas a more efficient implementation may validate more of the path as
it is building it, and backtrack to previous stages if it encounters validation failures or dead-
ends.
Also, the setCertStores method (inherited from the PKIXParameters class) is typically used by
a PKIX implementation of CertPathBuilder to find Certificates for path construction as well as
finding CRLs for path validation. This provides an extensible mechanism for specifying where
to locate Certificates and CRLs.
This call creates a CertPathBuilder object that returns paths validated against the PKIX
algorithm.
The next step is to create a PKIXBuilderParameters object. This will be used to populate the PKIX
parameters used by the CertPathBuilder:
The next step is to specify the CertStore that the CertPathBuilder will use to look for
certificates and CRLs. For this example, we will populate a Collection CertStore with the
certificates and CRLs:
CollectionCertStoreParameters ccsp =
new CollectionCertStoreParameters(certsAndCrls);
CertStore store = [Link]("Collection", ccsp);
[Link](store);
The next step is to build the certification path using the input parameter set we have created:
try {
PKIXCertPathBuilderResult result =
(PKIXCertPathBuilderResult) [Link](params);
CertPath cp = [Link]();
} catch (CertPathBuilderException cpbe) {
[Link]("build failed: " + [Link]());
}
If the CertPathBuilder cannot build a path that meets the supplied parameters it will throw a
CertPathBuilderException. Otherwise, the validated certification path can be obtained from
the PKIXCertPathBuilderResult using the getCertPath method.
Once the checker has been instantiated, it can be added as a parameter using the
addCertPathChecker method of the PKIXParameters class:
[Link](checker);
Alternatively, a List of checkers can be added using the setCertPathCheckers method of the
PKIXParameters class.
certificates in the certification path. For example, a PKIXCertPathChecker that processes the
NameConstraints extension is stateful.
Also, the order in which the certificates processed by a service provider implementation are
presented (passed) to a PKIXCertPathChecker is very important, especially if the
implementation is stateful. Depending on the algorithm used by the service provider, the
certificates may be presented in reverse or forward order. A reverse ordering means that the
certificates are ordered from the most trusted CA (if present) to the target subject, whereas a
forward ordering means that the certificates are ordered from the target subject to the most
trusted CA. The order must be made known to the PKIXCertPathChecker implementation, so
that it knows how to process consecutive certificates.
All stateful implementations should clear or initialize any internal state in the checker. This
prevents a service provider implementation from calling a checker that is in an uninitialized
state. It also allows stateful checkers to be reused in subsequent operations without
reinstantiating them. The forward parameter indicates the order of the certificates presented to
the PKIXCertPathChecker. If forward is true, the certificates are presented from target to trust
anchor; if false, from trust anchor to target.
Forward Checking
The isForwardCheckingSupported method returns a boolean that indicates if the
PKIXCertPathChecker supports forward checking:
Supporting forward checking improves the efficiency of CertPathBuilders that build forward,
since it allows paths to be checked as they are built. However, some stateful
PKIXCertPathCheckers may find it difficult or impossible to support forward checking.
Supported Extensions
The getSupportedExtensions method returns an immutable Set of OID Strings for the X.509
extensions that the PKIXCertPathChecker implementation supports (i.e., recognizes, is able to
process):
The method should return null if no extensions are processed. All implementations should
return the Set of OID Strings that the check method may process.
A CertPathBuilder can use this information to identify certificates with unrecognized critical
extensions, even when performing a forward build with a PKIXCertPathChecker that does not
support forward checking.
If the certificate does not pass the check(s), a CertPathValidatorException should be thrown.
Cloning a PKIXCertPathChecker
The PKIXCertPathChecker class implements the Cloneable interface. All stateful
PKIXCertPathChecker implementations must override the clone method if necessary. The
default implementation of the clone method calls the [Link] method, which performs a
simple clone by copying all fields of the original object to the new object. A stateless
implementation should not override the clone method. However, all stateful implementations
must ensure that the default clone method is correct, and override it if necessary. For example,
a PKIXCertPathChecker that stores state in an array must override the clone method to make
a copy of the array, rather than just a reference to the array.
The reason that PKIXCertPathChecker objects are Cloneable is to allow a PKIX
CertPathBuilder implementation to efficiently backtrack and try another path when a potential
certification path reaches a dead end or point of failure. In this case, the implementation is able
to restore prior path validation states by restoring the cloned objects.
Example 9-3 Sample Code to Check for a Private Extension
This is an example of a stateless PKIXCertPathChecker implementation. It checks if a private
extension exists in a certificate and processes it according to some rules.
import [Link];
import [Link].X509Certificate;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
/*
* Initialize checker
*/
public void init(boolean forward)
throws CertPathValidatorException {
// nothing to initialize
}
/*
* Check certificate for presence of Netscape's
* private extension
* with OID "[Link].113730.1.1"
*/
public void check(Certificate cert,
Collection unresolvedCritExts)
throws CertPathValidatorException
{
X509Certificate xcert = (X509Certificate) cert;
byte[] ext =
[Link]("[Link].113730.1.1");
if (ext == null)
return;
//
// process private extension according to some
// rules - if check fails, throw a
// CertPathValidatorException ...
// {insert code here}
For each certificate that it validates, the service provider implementation must call the check
method of each PKIXCertPathChecker object in turn, passing it the certificate and any
remaining unresolved critical extensions:
/* clone checkers */
List newList = new ArrayList(checkers);
ListIterator li = [Link]();
while ([Link]()) {
PKIXCertPathChecker checker = (PKIXCertPathChecker) [Link]();
[Link]([Link]());
}
CertificateFactory cf = [Link]("X.509");
X509Certificate c;
try (InputStream in = new FileInputStream("x509_ca-[Link]")) {
c = (X509Certificate)[Link](in);
}
Similarly, here is a simple implementation of getCertPath() that loads a certificate path from a
file:
CertPath cp;
try (InputStream in = new FileInputStream("certpath.pkcs7")) {
cp = [Link](in, "PKCS7");
}
return cp;
}
Note that PKCS#7 does not require a specific order for the certificates in the file, so this code
only works for certification path validation when the certificates are ordered starting from the
entity to be validated and progressing back toward the CA root. If the certificates are not in the
right order, you need to do some additional processing. CertificateFactory has a
generateCertPath() method that accepts a Collection, which is useful for this type of
processing.
Adding in a PKIXCertPathChecker
import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
if (key != null) {
RSAKey rsaKey = (RSAKey)key;
int size = [Link]().bitLength();
if (size < 2048) return false;
}
return true;
}
}
Follow these general steps to check the revocation status of a certificate path with the
PKIXRevocationChecker class:
In this excerpt, the SOFT_FAIL option causes the revocation checker to ignore any network
failures (such as failing to establish a connection to the OCSP server) when it checks the
revocation status.
put("[Link]",
"[Link]")
In addition, service attributes can be defined for the certification path services. These attributes
can be used as filters for selecting service providers. See Appendix A for the definition of some
standard service attributes. For example, a provider may set the ValidationAlgorithm service
attribute to the name of an RFC or specification that defines the PKIX validation algorithm:
• The algorithm it uses to select and sort potential certificates. For example, given two
certificates that are potential candidates for the next certificate in the path, what criteria are
used to select one before the other? What criteria are used to reject a certificate?
• If applicable, the algorithm it uses for backtracking or constructing another path (i.e., when
potential paths do not meet constraints).
• The types of CertStore implementations that have been tested. The implementation
should be designed to work with any CertStore type, but this information may still be
useful.
All CertPathBuilder implementations should provide additional debugging support, in order to
analyze and correct potential path building problems. Details on how to access this debugging
information should be documented.
Certificate/CRL Stores
A provider should document what types of certificates and CRLs (and the version numbers, if
relevant) are retrieved by the CertStore.
A provider should also document any relevant information regarding the CertStore
implementation (such as protocols used or formats supported). For example, an LDAP
CertStore implementation should describe which versions of LDAP are supported and which
standard attributes are used for finding certificates and CRLs. It should also document if the
implementation caches results, and for how long (i.e., under what conditions are they
refreshed).
If the implementation returns the certificates and CRLs in a particular order, it should describe
the sorting algorithm. An implementation should also document any additional or default
initialization parameters. Finally, an implementation should document if and how it uses
information in the CertSelector or CRLSelector objects to find certificates and CRLs.
Service Interdependencies
Common types of algorithm interdependencies in certification path service implementations.
The following are some common types of algorithm interdependencies in certification path
service implementations:
• Certification Path Validation and Signature Algorithms
A CertPathValidator implementation often requires use of a signature algorithm to verify
each certificate's digital signature. The setSigProvider method of the PKIXParameters
class allows a user to specify a specific Signature provider.
• Certification Path Builders and Certificate Factories
A CertPathBuilder implementation will often utilize a CertificateFactory to generate a
certification path from a list of certificates.
• CertStores and Certificate Factories
A CertStore implementation will often utilize a CertificateFactory to generate
certificates and CRLs from their encodings. For example, an LDAP CertStore
implementation may use an X.509 CertificateFactory to generate X.509 certificates and
CRLs from their ASN.1 encoded form.
You may need to extend these classes in your service provider implementation.
For example, a CertPathBuilder implementation may provide additional information such as
debugging traces when a CertPathBuilderException is thrown. The implementation may
throw a subclass of CertPathBuilderException that holds this information. Likewise, a
CertStore implementation can provide additional information when a failure occurs by throwing
a subclass of CertStoreException . Also, you may want to implement a subclass of
CertificateFactory
The "SUN" provider for the CertificateFactory engine class supports generation of X.509
CertPath objects. The PKCS7 and PkiPath encodings are supported. The PKCS#7
implementation supports a subset of RFC 2315 (only the SignedData ContentInfo type is
supported). The certificates in the CertPath are ordered in the forward direction (from target to
trust anchor). Each certificate in the CertPath is of type
[Link].X509Certificate , and versions 1, 2 and 3 are supported.
CertPathValidator
The "SUN" provider supplies a PKIX implementation of the CertPathValidator engine class.
The implementation validates CertPaths of type X.509 and implements the certification path
validation algorithm defined in RFC 5280: PKIX Certificate and CRL Profile. This
implementation sets the ValidationAlgorithm service attribute to "RFC5280".
Weak cryptographic algorithms can be disabled in the "SUN" provider using the
[Link] Security Property. See Appendix E: Disabling
Cryptographic Algorithms for a description and examples of this property.
The PKIX Certificate and CRL Profile has many optional features. The "SUN" provider
implements support for the policy mapping, authority information access and CRL distribution
point certificate extensions, the issuing distribution point CRL extension, and the reason code
and certificate issuer CRL entry extensions. It does not implement support for the freshest CRL
or subject information access certificate extensions. It also does not include support for the
freshest CRL and delta CRL Indicator CRL extensions and the invalidity date and hold
instruction code CRL entry extensions.
The implementation supports a CRL revocation checking mechanism that conforms to section
6.3 of the PKIX Certificate and CRL Profile. OCSP (RFC 2560) is also currently supported as a
built in revocation checking mechanism. See Appendix C: OCSP Support for more details on
the implementation and configuration and how it works in conjunction with CRLs.
The implementation does not support the nameConstraints parameter of the TrustAnchor
class and the validate method throws an InvalidAlgorithmParameterException if it is
specified.
CertPathBuilder
The "SUN" provider supplies a PKIX implementation of the CertPathBuilder engine class. The
implementation builds CertPaths of type X.509. Each CertPath is validated according to the
PKIX algorithm defined in RFC 5280: PKIX Certificate and CRL Profile. This implementation
sets the ValidationAlgorithm service attribute to "RFC5280".
The implementation builds CertPath objects in a forward direction using a depth-first algorithm.
It backtracks to previous states and tries alternate paths when a potential path is determined to
be invalid or exceeds the PKIXBuilderParameters maxPathLength parameter.
This implementation has been tested with the LDAP and Collection CertStore implementations
included in this release of the "SUN" provider.
Debugging support can be enabled by setting the [Link] property to certpath.
For example:
Collection CertStore
The SUN provider supports the Collection implementation of the CertStore engine class.
The Collection CertStore implementation can hold any objects that are an instance of
[Link] or [Link].
The certificates and CRLs are not returned in any particular order and will not contain
duplicates.
If set to true, Oracle's PKIX implementation uses the information in a certificate's CRL
Distribution Points extension (in addition to CertStores that are specified) to find the CRL,
provided the distribution point is an X.500 distinguished name or a URI of type ldap, http, or ftp.
Note
Depending on your network and firewall setup, it may be necessary to also configure
your networking proxy servers.
Note
Depending on your network and firewall setup, it may be necessary to also configure
your networking proxy servers.
[Link]=http://
[Link]
[Link]="CN=OCS
P Responder, O=XYZ Corp"
[Link]="CN=Ente
rprise CA, O=XYZ Corp"
[Link]=2A:FF:
00
These properties may be set either statically in the Java runtime's <java_home>/conf/
security/[Link] file, or dynamically using the
[Link]() method.
By default, OCSP checking is not enabled. It is enabled by setting the [Link] property to
"true". Use of the remaining properties is optional. Note that enabling OCSP checking only
has an effect if revocation checking has also been enabled. Revocation checking is enabled
via the [Link]() method.
OCSP checking works in conjunction with Certificate Revocation Lists (CRLs) during
revocation checking. The following is a summary of the interaction of OCSP and CRLs.
Failover to CRLs occurs only if an OCSP problem is encountered. Failover does not occur if
the OCSP responder confirms either that the certificate has been revoked or that it has not
been revoked.
LDAP CertStore
The LDAP CertStore implementation retrieves certificates and CRLs from an LDAP directory
using the LDAP schema defined in RFC 2587.
The LDAPSchema service attribute is set to "RFC2587".
The implementation fetches certificates from different locations, depending on the values of the
subject, issuer, and basicConstraints selection criteria specified in the X509CertSelector. It
performs as many of the following operations as possible:
1. Subject non-null, basicConstraints <= -1
Looks for certificates in the subject DN's "userCertificate" attribute.
2. Subject non-null, basicConstraints >= -1
Looks for certificates in the forward element of the subject DN's "crossCertificatePair"
attribute AND in the subject's "caCertificate" attribute.
3. Issuer non-null, basicConstraints >= -1
Looks for certificates in the reverse element of the issuer DN's "crossCertificatePair"
attribute AND in the issuer DN's "caCertificate" attribute.
In each case, certificates are checked using [Link]() before adding
them to the resulting collection.
If none of the conditions specified previously applies, then an exception is thrown to indicate
that it was impossible to fetch certificates using the criteria supplied. Note that even if one or
more of the conditions apply, the Collection returned may still be empty if there are no
certificates in the directory.
The implementation fetches CRLs from the issuer DNs specified in the
setCertificateChecking, addIssuerName or setIssuerNames methods of the
X509CRLSelector class. If no issuer DNs have been specified using one of these methods, the
implementation throws an exception indicating it was impossible to fetch CRLs using the
criteria supplied. Otherwise, the CRLs are searched as follows:
1. The implementation first creates a list of issuer names. If a certificate was specified in the
setCertificateChecking method, it uses the issuer of that certificate. Otherwise, it
uses the issuer names specified using the addIssuerName or setIssuerNames
methods.
2. Next, the implementation iterates through the list of issuer names. For each issuer name, it
searches first in the issuer's "authorityRevocationList" attribute and then, if no
matching CRL was found there, in the issuer's "certificateRevocationList" attribute.
One exception is that if the issuer name was obtained from the certificate specified in the
setCertificateChecking method, it only checks the issuer's
"authorityRevocationList" attribute if the specified certificate is a CA certificate.
3. All CRLs are checked using [Link]() before adding them to the
resulting collection.
4. If no CRLs satisfying the selection criteria can be found, an empty Collection is returned.
Caching
By default each LDAP CertStore instance caches lookups for a maximum of 30 seconds. The
cache lifetime can be changed by setting the system property
[Link] to a value in seconds. A value of 0 disables
the cache completely. A value of -1 means unlimited lifetime.
In this syntax:
MD2
Any MD2-based algorithm will be blocked.
For example, a certificate, CRL, or OCSPResponse signed with an MD2withRSA signature
algorithm.
MD5
Any MD5-based algorithm will be blocked.
For example, a certificate, CRL, or OCSPResponse signed with an MD5withRSA signature
algorithm.
Note
The algorithm restrictions specified by this Security Property do not apply to trust
anchors or self-signed certificates.
Simple Authentication and Security Layer, or SASL, is an Internet standard (RFC 2222) that
specifies a protocol for authentication and optional establishment of a security layer between
client and server applications. SASL defines how authentication data is to be exchanged but
does not itself specify the contents of that data. It is a framework into which specific
authentication mechanisms that specify the contents and semantics of the authentication data
can fit.
SASL is used by protocols, such as the Lightweight Directory Access Protocol, version 3
(LDAP v3), and the Internet Message Access Protocol, version 4 (IMAP v4) to enable
pluggable authentication. Instead of hardwiring an authentication method into the protocol,
LDAP v3 and IMAP v4 use SASL to perform authentication, thus enabling authentication via
various SASL mechanisms.
There are a number of standard SASL mechanisms defined by the Internet community for
various levels of security and deployment scenarios. These range from no security (for
example, anonymous authentication) to high security (for example, Kerberos authentication)
and levels in between.
SASL, JSSE, and Java GSS are often used together. For example, a common pattern is for an
application to use JSSE for establishing a secure channel, and to use SASL for client,
username/password-based authentication. There are also SASL mechanisms layered on top of
GSS-API mechanisms; one popular example is a SASL GSS-API/Kerberos v5 mechanism that
is used with LDAP.
With the exception of defining and building protocols from scratch, protocol definition is often
the biggest factor in determining which API to use. For example, LDAP and IMAP are defined
to use SASL, so software related to these protocols should use the Java SASL API. When
building Kerberos applications and services, the API to use is Java GSS. When building
applications and services that use SSL/TLS as their protocol, the API to use is JSSE.
Based on the availability of the mechanisms supported by the platform and other configuration
information provided via the parameters, the Java SASL framework selects one of the listed
mechanisms and return an instance of SaslClient.
The name of the selected mechanism is usually transmitted to the server via the application
protocol. Upon receiving the mechanism name, the server creates a corresponding
SaslServer object to process client-sent responses. Here is an example of how the server
would create an instance of SaslServer.
SaslServer ss = [Link](
mechanism, protocol, myName, props, callbackHandler);
// Read response
msg = receive();
while (![Link]() && ([Link] == CONTINUE || [Link] ==
SUCCESS)) {
// Evaluate server challenge
response = [Link]([Link]);
if ([Link] == SUCCESS) {
// done; server doesn't expect any more SASL data
if (response != null) {
throw new IOException(
"Protocol error: attempting to send response after
completion");
}
break;
} else {
send(mechanism, response);
msg = receive();
}
}
The client application iterates through each step of the authentication by using the mechanism
(sc) to evaluate the challenge gotten from the server and to get a response to send back to the
server. It continues this cycle until either the mechanism or application-level protocol indicates
that the authentication has completed, or if the mechanism cannot evaluate a challenge. If the
mechanism cannot evaluate the challenge, it throws an exception to indicate the error and
terminates the authentication. Disagreement between the mechanism and protocol about the
completion state must be treated as an error because it might indicate a compromise of the
authentication exchange.
Here is an example of how a server might use SaslServer.
// Read request that contains mechanism name and optional initial response
[Link]();
if ([Link]()) {
send(mechanism, challenge, SUCCESS);
} else {
send(mechanism, challenge, CONTINUE);
[Link]();
}
} catch (SaslException e) {
send(ERROR);
[Link]();
break;
}
}
The server application iterates through each step of the authentication by giving the client's
response to the mechanism (ss) to process. If the response is incorrect, the mechanism
indicates the error by throwing a SaslException so that the server can report the error and
terminate the authentication. If the response is correct, the mechanism returns challenge data
to be sent to the client and indicates whether the authentication is complete. Note that
challenge data can accompany a "success" indication. This might be used, for example, to tell
the client to finalize some negotiated state.
A security layer has been negotiated if the [Link] property indicates that either integrity
and/or confidentiality has been negotiated.
To communicate with the peer using the negotiated layer, the application first uses the wrap
method to encode the data to be sent to the peer to produce a "wrapped" buffer. It then
transfers a length field representing the number of octets in the wrapped buffer followed by the
contents of the wrapped buffer to the peer. The peer receiving the stream of octets passes the
buffer (without the length field) to unwrap to obtain the decoded bytes sent by the peer. Details
of this protocol are described in RFC 2222. Example 10-1 illustrates how a client application
sends and receives application data using a security layer.
Example 10-1 Sample Code for SASL Client Send and Receive Data
[Link].7=SunSASL
To add or remove a SASL provider, you add or remove the corresponding line in the security
properties file. For example, if you want to add a SASL provider and have its mechanisms be
chosen over the same ones implemented by the SunSASL provider, then you would add a line
to the security properties file with a lower number.
[Link].7=[Link]
[Link].8=SunSASL
Alternatively, you can programmatically add your own provider using the
[Link] class. For example, the following sample code registers the
[Link] to the list of available SASL security providers.
[Link](new [Link]());
See Step 8: Prepare for Testing in Steps to Implement and Integrate a Provider for more
information about adding providers to the security properties file and programmatically adding
your own providers.
When an application requests a SASL mechanism by supplying one or more mechanism
names, the SASL framework looks for registered SASL providers that support that mechanism
by going through, in order, the list of registered providers. The providers must then determine
whether the requested mechanism matches the selection policy properties in the Sasl and if
so, return an implementation for the mechanism.
The selection policy properties specify the security aspects of a mechanism, such as its
susceptibility to certain attacks. These are characteristics of the mechanism (definition), rather
than its implementation so all providers should come to the same conclusion about a particular
mechanism. For example, the PLAIN mechanism is susceptible to plaintext attacks regardless
of how it is implemented. If no selection policy properties are supplied, there are no restrictions
on the selected mechanism. Using these properties, an application can ensure that it does not
use unsuitable mechanisms that might be deployed in the execution environment. For
example, an application might use the following sample code if it does not want to allow the
use of mechanisms susceptible to plaintext attacks.
Note
Some of these mechanisms are weak; you're responsible for determining whether the
algorithm meets the security requirements of your applications.
• Client Mechanisms
– PLAIN (RFC 2595). This mechanism supports cleartext user name/password
authentication.
– CRAM-MD5 (RFC 2195). This mechanism supports a hashed user name/password
authentication scheme.
– DIGEST-MD5 (RFC 2831). This mechanism defines how HTTP Digest Authentication
can be used as a SASL mechanism.
– EXTERNAL (RFC 2222). This mechanism obtains authentication information from an
external channel (such as TLS or IPsec).
– NTLM. This mechanism supports NTLM authentication.
• Server Mechanisms
– CRAM-MD5
– DIGEST-MD5
– NTLM
An application that uses these mechanisms from the SunSASL provider must supply the
required parameters, callbacks and properties. The properties have reasonable defaults and
only need to be set if the application wants to override the defaults. Most of the parameters,
callbacks, and properties are described in the API documentation. The following sections
describe mechanism-specific behaviors and parameters not already covered by the API
documentation.
Cram-MD5
The Cram-MD5 client mechanism uses the authorization id parameter, if supplied, as the
default user name in the NameCallback to solicit the application/end-user for the authentication
id. The authorization id is otherwise not used by the Cram-MD5 mechanism; only the
authentication id is exchanged with the server.
Digest-MD5
The Digest-MD5 mechanism is used for digest authentication and optional establishment of a
security layer. It specifies the following ciphers for use with the security layer: Triple DES, DES
and RC4 (128, 56, and 40 bits). The Digest-MD5 mechanism can support only ciphers that are
available on the platform. For example, if the platform does not support the RC4 ciphers, then
the Digest-MD5 mechanism will not use those ciphers.
The [Link] property supports high, medium, and low settings; its default is
high,medium,low. The ciphers are mapped to the strength settings as follows:
When there is more than one choice for a particular strength, the cipher selected depends on
the availability of the ciphers in the underlying platform. To explicitly name the cipher to use,
set the [Link] property to the corresponding cipher id. Note
that this property setting must be compatible with [Link] and the ciphers available in
the underlying platform. For example, [Link] being set to low and
[Link] being set to 3des are incompatible. The
[Link] property has no default.
NTLM
Note
This section applies both to the NTLM client mechanism and the NTLM server
mechanism.
NT LAN Manager (NTLM) is an security protocol from Microsoft used to access their various
services such as IIS Web Server and Exchange Mail Server. As a SASL mechanism, it can be
used to access Microsoft Exchange Server. It is also useful for HTTP authentication with the
NTLM scheme.
The NTLM mechanism is used for NTLM authentication. It does not provide a security layer.
This means that you can only set the [Link] environment property to auth.
If the LMCompatibilityLevel registry value is set to a high value on the server, certain low value
requests are not supported. However, there's no protocol for the server to inform the client to
use a higher version, so the user must manually choose the correct version on the client side.
Set the system property [Link] to any value to turn on debugging
An application that uses these mechanisms from the SunSASL provider must supply the
required parameters, callbacks and properties. The properties have reasonable defaults and
only need to be set if the application wants to override the defaults.
All users of server mechanisms must have a callback handler that deals with the
AuthorizeCallback. This is used by the mechanisms to determine whether the authenticated
user is allowed to act on behalf of the requested authorization id, and also to obtain the
canonicalized name of the authorized user (if canonicalization is applicable).
Most of the parameters, callbacks, and properties are described in the API documentation. The
following sections describe mechanism-specific behaviors and parameters not already covered
by the API documentation.
Cram-MD5
The Cram-MD5 server mechanism uses the NameCallback and PasswordCallback to obtain
the password required to verify the SASL client's response. The callback handler should use
the [Link]() as the key to fetch the password.
Digest-MD5
The Digest-MD5 server mechanism uses the RealmCallback, NameCallback, and
PasswordCallback to obtain the password required to verify the SASL client's response. The
callback handler should use [Link]() and
[Link]() as keys to fetch the password.
An application that uses the GSSAPI mechanism from the JdkSASL provider must supply the
required parameters, callbacks and properties. The properties have reasonable defaults and
only need to be set if the application wants to override the defaults. Most of the parameters,
callbacks, and properties are described in the API documentation. The following section
describes further GSSAPI behaviors and parameters not already covered by the API
documentation.
GSSAPI
Note
The GSSAPI server mechanism has the same requirements as the GSSAPI client
mechanism in terms of Kerberos credentials and the
[Link] property.
The GSSAPI mechanism is used for Kerberos v5 authentication and optional establishment of
a security layer. The mechanism expects the calling thread's Subject to contain the client's
Kerberos credentials or that the credentials could be obtained by implicitly logging in to
Kerberos. To obtain the client's Kerberos credentials, use the Java Authentication and
Authorization Service (JAAS) to log in using the Kerberos login module. See Introduction to
JAAS and Java GSS-API Tutorials for details and examples. After using JAAS authentication
to obtain the Kerberos credentials, you put the code that uses the SASL GSSAPI mechanism
within doAs or doAsPrivileged.
}
}
To obtain Kerberos credentials without doing explicit JAAS programming, see Use of Java
GSS-API for Secure Message Exchanges Without JAAS Programming. When using this
approach, there is no need to wrap the code within doAs or doAsPrivileged
An application that uses the GSSAPI mechanism from the JdkSASL provider must supply the
required parameters, callbacks and properties. The properties have reasonable defaults and
only need to be set if the application wants to override the defaults.
All users of server mechanism must have a callback handler that deals with the
AuthorizeCallback. This is used by the mechanism to determine whether the authenticated
user is allowed to act on behalf of the requested authorization id, and also to obtain the
canonicalized name of the authorized user (if canonicalization is applicable).
Most of the parameters, callbacks, and properties are described in the API documentation.
is [Link]. Here is a sample logging configuration file that enables the FINEST
logging level for the SunSASL provider:
[Link]=FINEST
handlers=[Link]
[Link]=FINEST
Table 10-7 shows the mechanisms and the logging output that they generate:
put("[Link]-MECH",
"[Link]");
A single SASL provider might be responsible for many mechanisms. Therefore, it might
have many invocations of put to register the relevant factories. The completed SASL
provider can then be made available to applications using the instructions described in
How SASL Mechanisms are Installed and Selected.
The Java XML Digital Signature API is a standard Java API for generating and validating XML
Signatures. This API was defined under the Java Community Process as JSR 105.
XML Signatures can be applied to data of any type, XML or binary (see XML Signature Syntax
and Processing). The resulting signature is represented in XML. An XML Signature can be
used to secure your data and provide data integrity, message authentication, and signer
authentication.
After providing a brief overview of XML Signatures and the XML Digital Signature API, this
document presents two examples that demonstrate how to use the API to validate and
generate an XML Signature. This document assumes that you have a basic knowledge of
cryptography and digital signatures.
The API is designed to support all of the required or recommended features of the W3C
Recommendation for XML-Signature Syntax and Processing. The API is extensible and
pluggable and is based on the Java Cryptography Service Provider Architecture; see Java
Cryptography Architecture (JCA) Reference Guide. The API is designed for two types of
developers:
• Developers who want to use the XML Digital Signature API to generate and validate XML
signatures
• Developers who want to create a concrete implementation of the XML Digital Signature
API and register it as a cryptographic service of a JCA provider (see The Provider Class).
Package Hierarchy
The following six packages, which are contained in the [Link] module, comprise
the XML Digital Signature API:
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
The [Link] package contains common classes that are used to perform XML
cryptographic operations, such as generating an XML signature or encrypting XML data. Two
notable classes in this package are the KeySelector class, which allows developers to
supply implementations that locate and optionally validate keys using the information contained
in a KeyInfo object, and the URIDereferencer class, which allows developers to create
and specify their own URI dereferencing implementations.
The [Link] package includes interfaces that represent the core elements
defined in the W3C XML digital signature specification. Of primary significance is the
XMLSignature class, which allows you to sign and validate an XML digital signature. Most of
the XML signature structures or elements are represented by a corresponding interface
(except for the KeyInfo structures, which are included in their own package and are discussed
in the next paragraph). These interfaces include: SignedInfo, CanonicalizationMethod,
SignatureMethod, Reference, Transform, DigestMethod, XMLObject, Manifest,
SignatureProperty, and SignatureProperties. The XMLSignatureFactory class is
an abstract factory that is used to create objects that implement these interfaces.
The [Link] package contains interfaces that represent most
of the KeyInfo structures defined in the W3C XML digital signature recommendation,
including KeyInfo, KeyName, KeyValue, X509Data, X509IssuerSerial,
RetrievalMethod, and PGPData. The KeyInfoFactory class is an abstract factory that is
used to create objects that implement these interfaces.
The [Link] package contains interfaces and classes representing
input parameters for the digest, signature, transform, or canonicalization algorithms used in the
processing of XML signatures.
Finally, the [Link] and [Link] packages
contains DOM-specific classes for the [Link] and [Link]
packages, respectively. Only developers and users who are creating or using a DOM-based
XMLSignatureFactory or KeyInfoFactory implementation will need to make direct use of
these packages.
Service Providers
A Java XML Signature is a concrete implementation of the abstract XMLSignatureFactory
and KeyInfoFactory classes and is responsible for creating objects and algorithms that
parse, generate and validate XML Signatures and KeyInfo structures. A concrete
implementation of XMLSignatureFactory must provide support for each of the required
algorithms as specified by the W3C recommendation for XML Signatures. It can optionally
support other algorithms as defined by the W3C recommendation or other specifications.
The Java XML Digital Signature API leverages the JCA provider model for registering and
loading XMLSignatureFactory and KeyInfoFactory implementations.
<Envelope xmlns="urn:envelope">
<Signature xmlns="[Link]
<!-- ... -->
</Signature>
</Envelope>
This Signature element has been inserted inside the content that it is signing, thereby making
it an enveloped signature. The required SignedInfo element contains the information that is
actually signed:
<Envelope xmlns="urn:envelope">
<Signature xmlns="[Link]
<SignedInfo>
<CanonicalizationMethod Algorithm="[Link]
c14n-20010315#WithComments"/>
<SignatureMethod Algorithm="[Link]
sha256"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="[Link]
signature"/>
</Transforms>
<DigestMethod Algorithm="[Link]
<DigestValue>/juoQ4bDxElf1M+KJauO20euW+QAvvPP0nDCruCQooM=</
DigestValue>
</Reference>
</SignedInfo>
<!-- ... -->
</Signature>
</Envelope>
The required CanonicalizationMethod element defines the algorithm used to canonicalize the
SignedInfo element before it is signed or validated. Canonicalization is the process of
converting XML content to a canonical form, to take into account changes that can invalidate a
signature over that data. Canonicalization is necessary due to the nature of XML and the way it
is parsed by different processors and intermediaries, which can change the data such that the
signature is no longer valid but the signed data is still logically equivalent.
The required SignatureMethod element defines the digital signature algorithm used to
generate the signature, in this case RSA with SHA-256.
One or more Reference elements identify the data that is digested. Each Reference element
identifies the data via a URI. In this example, the value of the URI is the empty String (""),
which indicates the root of the document. The optional Transforms element contains a list of
one or more Transform elements, each of which describes a transformation algorithm used to
transform the data before it is digested. In this example, there is one Transform element for the
enveloped transform algorithm. The enveloped transform is required for enveloped signatures
so that the signature element itself is removed before calculating the signature value. The
required DigestMethod element defines the algorithm used to digest the data, in this case
SHA-256. Finally the required DigestValue element contains the actual base64-encoded
digested value.
The required SignatureValue element contains the base64-encoded signature value of the
signature over the SignedInfo element.
The optional KeyInfo element contains information about the key that is needed to validate the
signature:
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>
9hSmAKw/4TTw/1l1u1pYzdFm6lOjRB/5NfdGWl/fB8iAa/tiK0f1u/VWoK6SMtogYgSDKqQThbAu
9dy9rRnOWRGY2He1JtpOvGh0WCmIFUEs2P22HvEf+JGKVEpkoP4hv53ucT69T+7nKGK3/bjxgp+T
C7fbnVj651+jAHuDFlC8Txt1R8ZymfN5cUeHIH96dvNFrtai/uwZDbVMfhV9chL//+Vyhx4O5nHv
jfS+0So9Qi52YAbEyLu6+BLdu8wnMWapC88CfXsRwrpx8b6aCU0e6QSZyOvdgXWz3+9ifVTBDIxE
kjhL5OASx0qjvc+dPUOMvq7fJE05RRZLyb0YJw==
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
This KeyInfo element contains a KeyValue element, which in turn contains a RSAKeyValue
element consisting of the public key needed to validate the signature. KeyInfo can contain
various content such as X.509 certificates and PGP key identifiers. See The KeyInfo Element
in XML Signature Syntax and Processing for more information on the different KeyInfo types.
Validate Example
To compile and run the example, execute the following commands:
$ javac [Link]
$ java Validate [Link]
The sample program will validate the signature in the file [Link] in the current
working directory.
Example 11-1 [Link]
import [Link].*;
import [Link].*;
import [Link].*;
import [Link];
import [Link].*;
import [Link];
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
/**
* This is a simple example of validating an XML Signature using
* the XML Signature API. It assumes the key needed to validate
* the signature is contained in a KeyValue KeyInfo.
*/
public class Validate {
//
// Synopsis: java Validate [document]
//
// where "document" is the name of a file containing the XML document
// to be validated.
//
public static void main(String[] args) throws Exception {
/**
* KeySelector which retrieves the public key out of the
* KeyValue element and returns it.
* NOTE: If the key algorithm doesn't match signature algorithm,
* then the public key will be ignored.
*/
private static class KeyValueKeySelector extends KeySelector {
public KeySelectorResult select(KeyInfo keyInfo,
[Link] purpose,
AlgorithmMethod method,
XMLCryptoContext context)
throws KeySelectorException {
if (keyInfo == null) {
throw new KeySelectorException("Null KeyInfo object!");
}
SignatureMethod sm = (SignatureMethod) method;
List<XMLStructure> list = [Link]();
}
}
}
<Envelope xmlns="urn:envelope">
</Envelope>
C7fbnVj651+jAHuDFlC8Txt1R8ZymfN5cUeHIH96dvNFrtai/uwZDbVMfhV9chL//+Vyhx4O5nHv
jfS+0So9Qi52YAbEyLu6+BLdu8wnMWapC88CfXsRwrpx8b6aCU0e6QSZyOvdgXWz3+9ifVTBDIxE
kjhL5OASx0qjvc+dPUOMvq7fJE05RRZLyb0YJw==
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</Envelope>
[Link](true);
Next, we use the factory to get an instance of a DocumentBuilder, which is used to parse
the document:
NodeList nl =
[Link]([Link], "Signature");
if ([Link]() == 0) {
This returns a list of all Signature elements in the document. In this example, there is only
one Signature element.
The validate method returns "true" if the signature validates successfully according to the core
validation rules in the W3C XML Signature Recommendation, and false otherwise.
If the [Link] method returns false, we can try to narrow down the cause
of the failure. There are two phases in core XML Signature validation:
• Signature validation (the cryptographic verification of the signature)
• Reference validation (the verification of the digest of each reference in the signature)
Each phase must be successful for the signature to be valid. To check if the signature failed to
cryptographically validate, we can check the status, as follows:
boolean sv = [Link]().validate(valContext);
[Link]("signature validation status: " + sv);
We can also iterate over the references and check the validation status of each one, as
follows:
Iterator<Reference> i =
[Link]().getReferences().iterator();
for (int j=0; [Link](); j++) {
boolean refValid = [Link]().validate(valContext);
[Link]("ref["+j+"] validity status: " + refValid);
}
Using KeySelectors
KeySelectors are used to find and select keys that are needed to validate an
XMLSignature. Earlier, when we created a DOMValidateContext object, we passed a
KeyValueKeySelector object as the first argument:
Alternatively, we could have passed a PublicKey as the first argument if we already knew
what key is needed to validate the signature. However, we often don't know.
The KeyValueKeySelector class is a concrete implementation of the abstract KeySelector
class. The KeyValueKeySelector implementation tries to find an appropriate validation key
using the data contained in KeyValue elements of the KeyInfo element of an
XMLSignature. It does not determine if the key is trusted. This is a very simple
KeySelector implementation, designed for illustration rather than real-world usage. A more
practical example of a KeySelector is one that searches a KeyStore for trusted keys that
match X509Data information (for example, X509SubjectName, X509IssuerSerial,
X509SKI, or X509Certificate elements) contained in a KeyInfo.
GenEnveloped Example
To compile and run this sample, execute the following command:
$ javac [Link]
$ java GenEnveloped [Link] [Link]
The sample program will generate an enveloped signature of the document in the file
[Link] and store it in the file [Link] in the current working
directory.
import [Link].*;
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link];
import [Link];
import [Link].*;
import [Link];
import [Link];
import [Link];
/**
* This is a simple example of generating an Enveloped XML
* Signature using the Java XML Digital Signature API. The
* resulting signature will look like (key and signature
* values will be different):
*
* <pre><code>
*<Envelope xmlns="urn:envelope">
* <Signature xmlns="[Link]
* <SignedInfo>
* <CanonicalizationMethod Algorithm="[Link]
c14n-20010315"/>
* <SignatureMethod Algorithm="[Link]
sha256"/>
* <Reference URI="">
* <Transforms>
* <Transform Algorithm="[Link]
signature"/>
* </Transforms>
* <DigestMethod Algorithm="[Link]
* <DigestValue>/
juoQ4bDxElf1M+KJauO20euW+QAvvPP0nDCruCQooM=<DigestValue>
* </Reference>
* </SignedInfo>
* <SignatureValue>
* YeS+F0uiYv0h946M69Q9pKFNnD6dxUwLA8QT3GX/0H3cSPKRnNFyZiR4RPgaA1ir/
ztb4rt6Lqb8
*
hgwPERIa5qhoGUJyHDfUTcQ0Xqn1jYCVoC3ho+oUgJPXNVgtMAtpvOgxcWXUPATYdyimO6RrHF8+
*
JXDkeICI9BPA4NKN1i77CAy6JJbaA87aNIpMJPImwJf8CM7mYsXremZz+RsafNE2cXXRzAoNOynC
* pi4oPYpE7CBLzhd23gf7zYRoyT06/
bVIj4j3qOlVY1TQofsQ20NtAz6PbqAs7QkNoDzkX1CYlDSJ
* U8cGHuwXpul/UIpOiL6MZF8I/YI4ZlJn+O8Mvg==
* </SignatureValue>
* <KeyInfo>
* <KeyValue>
* <RSAKeyValue>
* <Modulus>
* mH0S/
iw2K2tFTFHI75BtB67pzjR52HvQ8K7Xi5UX3NJm0oA+KX2mm0IrVcUuv609vbAAyQoW7CWm
* 4kswVgStCm68dlw36309cxrEmPhG+PKBmUaGuBmRzwityjXRyRZJ6yaLenE8SJO/
DC5ntQvmHqQQ
*
qeOJYvz2Cbi2bi6x9XwmpqOfZCE5iTvYwioEsrglhP1uLG9fiXyNR2PXUTyLqD91HLhZFj1CEiU7
* aE+
+WfkKaowIx5p8e3F6hQ+VFRNXjtemK5aajuL0gwU+Oujg9ijgbyMh19vBoI8LruJoMOBrYFNN
* 2boQJ3wP0Ek7CPIqAzQB5MnmvKc9jICKiiZVZw==
* </Modulus>
* <Exponent>AQAB</Exponent>
* </RSAKeyValue>
* </KeyValue>
* </KeyInfo>
* </Signature>
*</Envelope>
* </code></pre>
*/
public class GenEnveloped {
//
// Synopsis: java GenEnveloped [document] [output]
//
// where "document" is the name of a file containing the XML document
// to be signed, and "output" is the name of the file to store the
// signed document. The 2nd argument is optional - if not specified,
// standard output will be used.
//
public static void main(String[] args) throws Exception {
TransformerFactory tf = [Link]();
Transformer trans = [Link]();
[Link](new DOMSource(doc), new StreamResult(os));
}
}
<Envelope xmlns="urn:envelope">
</Envelope>
signing. The example uses DOM (the Document Object Model) to parse the XML document to
be signed and a DOM implementation to generate the resulting signature.
A basic knowledge of XML Signatures and their different components is helpful for
understanding this section. See XML Signature Syntax and Processing Version 1.1 for more
information.
[Link](true);
Next, we use the factory to get an instance of a DocumentBuilder, which is used to parse
the document:
In practice, the private key is usually previously generated and stored in a KeyStore file with
an associated public key certificate.
We then invoke various factory methods to create the different parts of the XMLSignature
object. We create a Reference object, passing to it the following:
• The URI of the object to be signed (We specify a URI of "", which implies the root of the
document.)
• The DigestMethod (we use SHA256)
• A single Transform, the enveloped Transform, which is required for enveloped
signatures so that the signature itself is removed before calculating the signature value
Next, we create the SignedInfo object, which is the object that is actually signed. When
creating the SignedInfo, we pass as parameters:
SignedInfo si = [Link]
([Link]
(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
[Link]("[Link]
sha256", null),
[Link](ref));
Next, we create the optional KeyInfo object, which contains information that enables the
recipient to find the key needed to validate the signature. In this example, we add a KeyValue
object containing the public key. To create KeyInfo and its various subtypes, we use a
KeyInfoFactory object, which can be obtained by invoking the getKeyInfoFactory
method of the XMLSignatureFactory, as follows:
We then use the KeyInfoFactory to create the KeyValue object and add it to a KeyInfo
object:
KeyValue kv = [Link]([Link]());
KeyInfo ki = [Link]([Link](kv));
Finally, we create the XMLSignature object, passing as parameters the SignedInfo and
KeyInfo objects that we created earlier:
Notice that we haven't actually generated the signature yet; we'll do that in the next step.
[Link](dsc);
The resulting document now contains a signature, which has been inserted as the last child
element of the root element.
OutputStream os;
if ([Link] > 1) {
os = new FileOutputStream(args[1]);
} else {
os = [Link];
}
TransformerFactory tf = [Link]();
Transformer trans = [Link]();
[Link](new DOMSource(doc), new StreamResult(os));
• External Entity Reference: Refers to external data, the following is the syntax:
<Book xmlns:xi="[Link]
<xi:include href=[Link]"/>
<xi:include href=[Link]"/>
<xi:include href=[Link]"/>
<xi:include href=[Link]"/>
</Book>
• References to XML Schema components using the schemaLocation attribute and import
and include elements, for example:
<xs:schema xmlns:xs="[Link]
<xs:include schemaLocation="[Link]
[Link]"/>
<!-- ... -->
</xs:schema>
• Combining style sheets using import or include elements, the following is the syntax:
<xsl:include href="[Link]"/>
• XSLT document() function: Used to access nodes in an external XML document, for
example:
When an XML parser encounters such a document, it will attempt to resolve the entity
declaration by expanding the references. Because the references are nested, the expansion
becomes exponential by the number of entities each refers to. Such a process can lead the
XML parser to consume 100% of CPU time and a large amount of memory, and eventually the
system runs out of memory.
read and access external resources, which helps remove a source of potential risk. See Using
Resolvers and Catalogs.
DocumentBuilderFactory factory =
[Link]();
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, true);
The explicit FSP setting enforces resource limits (see JAXP Properties for Processing
Limits ), disables external entity resolution (see External Access Properties ), prevents use
of third-party parser overrides (see Third-Party Parsers), and restricts XSLT extension
functions (see Extension Functions).
• JAXP Configuration File (JCF)
You can set security-related JAXP properties (see Configuring with JAXP Properties)
programmatically, through system properties, or by using the JAXP Configuration File
(JCF) (see Setting JAXP Properties in a JAXP Configuration File). Using the JCF provides
a convenient, code-free means of managing security settings across all XML processor
instances in the JVM.
• External Access Restrictions
Preventing arbitrary external access is essential for XML security. This can be achieved by
setting FSP on XML factories or, where more granular control is necessary, by configuring
External Access Properties (EAPe) (see External Access Properties ). Note that for the
StAX processor (see the [Link] package), FSP is not supported, so EAPs
must be used.
• Resolvers and Catalogs
Restricting all external access may be too limiting for some applications. To safely handle
external resources, implement resolvers or catalogs (see Using Resolvers and Catalogs).
These mechanisms allow fine-grained control over how external references are resolved
while blocking unwanted connections.
Note
While FSP is enabled by default in the JDK, the default configuration does not restrict
external entity resolution. For comprehensive security, explicitly set FSP through the
API and configure external access restrictions as needed.
JAXP APIs
JAXP consists of a set of APIs built XML technologies and standards that are essential for
XML processing. These include APIs for the following:
• Parsing: JAXP Parsing API ([Link] package, which is based on the
Document Object Model (DOM) ([Link] package) and Simple API for XML Parsing
(SAX) ([Link] package)
• Streaming API for XML (StAX) ([Link] package)
• Serializing: StAX and Extensible Stylesheet Language Transformations (XSLT)
([Link] package)
• Transformation: JAXP Transformation API ([Link] package) and XSLT
(Extensible Stylesheet Language Transformations)
• Querying and traversing XML documents: XML Path Language (XPath) API
([Link] package)
• Resolving external resources: XML Catalog API ([Link] package)
You can also set a System property's value with the method
[Link](String key, String name) or
[Link](Properties).
• Setting JAXP Properties in a JAXP Configuration File: You can set a JAXP property in a
JAXP configuration file named <java-home>/conf/[Link] .
Not all JAXP properties can be set by all of these ways. See the [Link] module summary
to determine which method you can set a specific JAXP property.
If you haven't set a particular JAXP property with one of these ways, then the Java runtime
uses the value specified in the default JAXP properties file. If a property doesn't exist in this
file, then the Java runtime uses its default value. However, if FEATURE_SECURE_PROCESSING
(FSP) is turned on, then the Java runtime uses a more restrictive value, if applicable. See the
table Implementation Specific Properties and Properties in the [Link] module summary for
more information.
XPathFactory xf = [Link]();
[Link](name, value);
[Link]("[Link]
entityExpansionLimit", "2000");
[Link]("[Link]
maxGeneralEntitySizeLimit", "100000");
[Link]("[Link]
maxParameterEntitySizeLimit", "10000");
[Link]("[Link]
"100");
[Link]("[Link]", "1000");
[Link]("[Link]", "20");
The following is an example of limiting a DOM parser to only local connections for external
DTDs:
If a parser module within the application handles untrusted sources, it may further restrict
access. The following code overrides those in the [Link] file and those specified
by System properties and enables the XML processor to read local files only:
DocumentBuilderFactory dbf =
[Link]();
[Link](XMLConstants.ACCESS_EXTERNAL_DTD, "file");
// ...
SchemaFactory schemaFactory =
[Link](XMLConstants.W3C_XML_SCHEMA_NS_URI);
[Link](XMLConstants.ACCESS_EXTERNAL_DTD, "file");
[Link](XMLConstants.ACCESS_EXTERNAL_SCHEMA, "file");
As described in Scope and Order of Setting JAXP Properties, JAXP properties specified
through JAXP factories have the narrowest scope, affecting only the processors created by the
factories, and therefore override any default settings, System properties, and those in the
[Link] file. By setting JAXP properties through JAXP factories, you can ensure
that your applications behave the same way regardless of which JDK release you're using or
whether JAXP properties are set through other means.
java -[Link]="file,http" -
[Link]="file, http" MyApp
To set JAXP properties for only a portion of the application, set their corresponding System
properties before the portion, and then clear them afterward. For example, if your application
requires access to external DTDs and schemas, then add these lines to your application's
initialization code block:
Then, once your application is done processing XML documents or before it exits, clear out the
properties as follows:
[Link]("[Link]");
[Link]("[Link]");
The following code, from Processing Limit Samples in The Java Tutorials, is another example
that shows how to do this for the processing limit maxGeneralEntitySizeLimit:
The following example allows the resolution of external schemas for a portion of an application:
Note
JAXP properties related to processing limits are specific to the JDK implementation
while those related to External Access Properties (EAPs) are standard properties.
[Link]=2000
[Link]=file, http
If you don't want to allow any external connection by XML processors, you can set all External
Access Properties (EAPs) to file only:
[Link]=file
[Link]=file
[Link]=file
If you want to prevent applications from accidentally reading external files through an XML
processor, set the EAPs as follows in the [Link] file as follows:
[Link]=""
[Link]=""
[Link]=""
Note
• Use the corresponding System property in the [Link] file. The
System properties that correspond to processing limits have the prefix [Link].
The System properties that correspond to EAPs have the prefix [Link].
• Processing limit values are integers. A NumberFormatException is thrown if a
processing limit's value is not a parsable integer; see the method
[Link](String).
• If the property is not set by the factory as in the previous example, a system property
setting will be in effect. The following command-line example sets the RESOLVE property to
continue for the application myApp:
• If the property is not set by the factory or in a system property, the setting in the JAXP
configuration file, <java_home>/conf/[Link], will take effect. The
following entry sets the RESOLVE property to continue.
[Link]=continue
• If the value of the RESOLVE property is not set anywhere, it will be resolved to its default
value, strict.
Security-Related Properties
The following sections describe the properties you can set to configure JAXP for secure XML
processing:
There are two kinds of JAXP security-related properties:
• API-Defined Properties: These are constant field values that are part of the Java SE API
whose values you set through a factory's or parser's setAttribute(String, Object) or
setProperty(String, Object) method. Some of these fields have corresponding system
properties you can set on the command line or in a JAXP configuration file:
– The FEATURE_SECURE_PROCESSING Security Directive
– External Access Properties
• JDK-Specific Properties: These are system properties you set through JAXP parsers or
factories, on the command line, or in a JAXP configuration file. Some of these aren't
system properties, which means you can't set their values on the command line:
– JAXP Properties for Processing Limits
– Extension Functions
– Third-Party Parsers
– Disabling DTD Processing
API-Defined Properties
Topics
• The FEATURE_SECURE_PROCESSING Security Directive
• External Access Properties
using a JAXP factory as follows, it instructs the JAXP processor (for example, a parser or
transformer) to apply security controls based on the processor's security model:
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, true);
When FSP is enabled, the JDK activates additional security measures using External Access
Properties (EAPs) and JDK-specific properties. See External Access Properties (EAPs) and
JDK-Specific Properties.
By default, the JDK turns FSP on for SAX, DOM, and validation factories. However, external
connections (such as external entity resolution or resource access) are not disabled by default.
To ensure external access is properly restricted, FSP needs to be explicitly set as shown
previously.
Note that when a Security Manager is present, JAXP security processing is turned on
automatically; otherwise, JAXP security processing is disabled by default.
Note
External connections are allowed even when FSP is on by default. Explicitly turning on
FSP through the API, for example,
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, true), is
necessary to disable all external connections.
• [Link].ACCESS_EXTERNAL_DTD
• [Link].ACCESS_EXTERNAL_SCHEMA
• [Link].ACCESS_EXTERNAL_STYLESHEET
Attribute Description
Name [Link]
accessExternalDTD
Definition Restricts access to external DTDs and external
entity references to the protocols specified.
Value See Values of EAPs
Default value all, connection permitted to all protocols
System property [Link]
Attribute Description
Name [Link]
accessExternalSchema
Definition Restricts access to the protocols specified for
external references set by the schemaLocation
attribute, import element, and include element.
Value See Values of EAPs
Default value all, connection permitted to all protocols.
System property [Link]
Attribute Description
Name [Link]
accessExternalStylesheet
Definition Restricts access to the protocols specified for
external references set by the stylesheet
processing instruction, document function, and
import and include elements.
Value See Values of EAPs
Default value all, connection permitted to all protocols.
System property [Link]
Values of EAPs
All EAPs have values of the same format:
• Value: A list of protocols separated by comma. A protocol is the scheme portion of an URI,
or in the case of the JAR protocol, jar plus the scheme portion separated by colon. A
scheme is defined as:
scheme = alpha *( alpha | digit | "+" | "-" | "." )
where alpha = a-z and A-Z.
The JAR protocol is defined as: jar[:scheme]
Protocols are case-insensitive. Any whitespace characters as defined by
[Link] in the value are ignored. Examples of protocols are file,
http, and jar:file.
• Default value: The default value is implementation specific. For the JDK, the default value
is all, which grants permissions to all protocols.
• Granting all access: The keyword all grants permission to all protocols. For example,
specifying [Link]=all in the [Link] file enables a
system to work as before with no restrictions on accessing external DTDs and entity
references.
• Denying any access: An empty string ("") means that no permission is granted to any
protocol. For example, specifying [Link]="" in the
[Link] file instructs JAXP processors to deny any external connections.
The XML processors, by default, attempt to connect and read external resources that are
referenced in XML sources. Note that this may potentially expose applications and systems to
risks posed by external connections. It's therefore recommended that applications consider
limiting external connections with EAPs.
Internal applications and systems that handle only trusted XML documents may not need these
EAPs. Applications and systems that rely on the Java Security Manager to regulate external
connections may also have no need for them. However, keep in mind that EAPs are specific to
the XML processors and are at the top layer of the process, which means that the processors
check these EAPs before any connections are made. They may therefore serve as an
additional and more direct protection against external connection risks.
You can use EAPs along with custom resolvers and catalogs (see Using Resolvers and
Catalogs) to effectively manage external connections and reduce risks.
Even in a trusted environment with trusted sources, it's recommended that you use both EAPs
and resolvers to minimize dependencies on external sources.
[Link] true
[Link] false
[Link] false
[Link] false
JDK-Specific Properties
Topics
• JAXP Properties for Processing Limits
• Extension Functions
• Third-Party Parsers
• Disabling DTD Processing
Attribute Description
Name [Link]
properties/elementAttributeLimit
Definition Limits the number of attributes an element can
have.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 10000
System property [Link]
Since 7u45, 8
Attribute Description
Name [Link]
properties/entityExpansionLimit
Definition Limits the number of entity expansions.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 64000
System property [Link]
Since 7u45, 8
Attribute Description
Name [Link]
properties/entityReplacementLimit
Attribute Description
Definition Limits the total number of nodes in all entity
references.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 3000000
System property [Link]
Since 7u111, 8u101
Attribute Description
Name [Link]
properties/maxElementDepth
Definition Limits the maximum element depth.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 0
System property [Link]
Since 7u65, 8u11
Attribute Description
Name [Link]
properties/maxGeneralEntitySizeLimit
Definition Limits the maximum size of any general entities.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 0
System property [Link]
Since 7u45, 8
Attribute Description
Name [Link]
properties/maxOccurLimit
Definition Limits the number of content model nodes that may
be created when building a grammar for a W3C
XML Schema that contains maxOccurs attributes
with values other than "unbounded".
Attribute Description
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 5000
System property [Link]
Since 7u45, 8
Attribute Description
Name [Link]
properties/maxParameterEntitySizeLimit
Definition Limits the maximum size of any parameter entities,
including the result of nesting multiple parameter
entities.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 1000000
System property [Link]
Since 7u45, 8
Attribute Description
Name [Link]
properties/maxXMLNameLimit
Definition Limits the maximum size of XML names, including
element name, attribute name and namespace
prefix and URI.
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 1000
System property [Link]
Since 7u91, 8u65
Attribute Description
Name [Link]
properties/totalEntitySizeLimit
Definition Limits the total size of all entities that include
general and parameter entities. The size is
calculated as an aggregation of all entities.
Attribute Description
Value A positive integer. A value less than or equal to 0
indicates no limit. If the value is not an integer, a
NumericFormatException is thrown.
Default value 5x10^7
System property [Link]
Since 7u45, 8
throws a fatal error once it has reached the entity expansion limit. By default,
entityExpansionLimit is set to 64,000.
The following command-line example sets the entity expansion limit to 10,000:
The following code example sets the entity expansion limit to 10,000:
[Link]("[Link]","10000");
The following code example sets the element attribute limit to 20:
[Link]("[Link]","20");
or simply run for a very long time. To prevent potential attacks that exploit this behavior, enable
secure processing on a factory as follows:
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, [Link]);
Note that for xsd:element and xsd:any, the validating parser uses a constant amount of
space, which is independent of the value of the maxOccurs occurrence indicator.
The default value of [Link] is 5000. This system property limits the number
of content model nodes that may be created when building a grammar for a W3C XML
Schema that contains maxOccurs occurrence indicators with values other than "unbounded".
When you run the processing limit sample with the DTD in W3C MathML 3.0, it prints out the
following table:
Table 12-15 Running JAXP Processing Limits Sample with DTD in W3C MatchML 3.0
In this example, the total number of entity references, or the entity expansion, is 1417; the
default limit is 64000. The total size of all entities is 55425; the default limit is 50000000. The
biggest parameter entity is %MultiScriptExpression with a length of 7303 after all references
are resolved; the default limit is 1000000.
If this is the largest file that the application is expected to process, it is recommended that the
limits be set to smaller numbers. For example, 2000 for ENTITY_EXPANSION_LIMIT, 100000 for
TOTAL_ENTITY_SIZE_LIMIT, and 10000 for PARAMETER_ENTITY_SIZE_LIMIT.
Extension Functions
Because Feature for Secure Processing (FSP) is off by default for Transformer and XPath,
extension functions are allowed. For applications processing documents from untrusted
sources, it is recommended to turn off the extension functions feature. There are two ways to
do so:
• By setting FSP to true, for example:
TransformerFactory tf = [Link]();
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, true);
In cases where extension functions are disabled as a result of installing a Java Security
Manager, applications may also choose to re-enable the extension functions feature by setting
the property enableExtensionFunctions to true. The following table defines this property:
Attribute Description
Name [Link]
properties/enableExtensionFunctions
Definition Determines whether XSLT and XPath extension
functions are allowed.
Value A boolean. True indicates that extension functions
are allowed; False otherwise.
Default value true
System property [Link]
Since 7u60
Third-Party Parsers
The JDK will always use its system-default parser even when there's a third-party parser on
the classpath. To override the JDK system-default parser, set the
[Link] property to true.
Attribute Description
Name [Link]
Definition Enables the use of a third-party's parser
implementation to override the system-default
parser for the JDK's Transformer,
Validator, and XPath implementations. The
property can be set through JAXP factories,
System properties, or the [Link]
file.
Value A boolean. Setting it to true enables third-party
parser implementations to override the system-
default implementation during XML transformation,
XML validation, or XPath operations. Setting it to
false disables the use of third-party parser
implementations. When the value is specified as a
String, the returning value will be that of
[Link].
Default value false
System property [Link]
Since 6u181, 7u171, 8u161, 9.0.4
The following code snippets instruct the factories to use a third-party parser, if found on the
classpath, by setting the [Link] property with the setFeature
method:
[Link](JDK_OVERRIDE_PARSER, true);
...
XPathFactory xf = [Link]();
[Link](JDK_OVERRIDE_PARSER, true);
...
SchemaFactory schemaFactory =
[Link](XMLConstants.W3C_XML_SCHEMA_NS_URI);
[Link](JDK_OVERRIDE_PARSER, true);
...
Schema schema = [Link](new File("[Link]"));
Validator validator = [Link]();
[Link](JDK_OVERRIDE_PARSER, true);
[Link]("[Link]", "true"));
You can add the following line to the [Link] file to enable third-party parsers:
[Link]=true
Composite Processors
Composite processors such as the validator, transformer, and XPath processor use internally
created parsers to read the source when it's not a DOMSource or Document. When
FEATURE_SECURE_PROCESSING (FSP) is turned on through factories such as
For example, the following code creates an instance of XPathFactory with FSP:
XPathFactory xf = [Link]();
[Link](XMLConstants.FEATURE_SECURE_PROCESSING, true);
This process ensures FSP is also on for any internal parser required by the XPath processor,
such as when it's used to evaluate raw XML source. Consequently, any restrictions defined by
the parser are applied. For instance, if the XML source contains external references not
resolved by a catalog or resolver, it will be rejected as described in External Access Properties
because FSP is turned on explicitly.
package [Link];
DocumentBuilder builder =
[Link]().newDocumentBuilder();
[Link](resolver);
package [Link];
package [Link];
package [Link];
SchemaFactory schemaFactory =
[Link]("[Link]
LSResourceResolver resolver = ...;
[Link](resolver);
Catalog Resolver
You can use a CatalogResolver as a custom resolver that substitutes external references
with local resources configured as Catalog objects. You can register a CatalogResolver
on factories or processors in place of EntityResolver, XMLResolver, URIResolver or
LSResourceResolver as described in Java XML Resolvers. In the following code snippet, a
CatalogResolver is registered as an EntityResolver on a SAXParserFactory:
For more examples, see XML Catalog API in Java Platform, Standard Edition Java Core
Libraries Developer's Guide.
When input files contain constructs that cause an over-the-limit exception, applications may
check the error code to determine the nature of the failure. The following error codes are
defined for processing limits:
• EntityExpansionLimit: JAXP00010001
• ElementAttributeLimit: JAXP00010002
• MaxEntitySizeLimit: JAXP00010003
• TotalEntitySizeLimit: JAXP00010004
• MaxXMLNameLimit: JAXP00010005
• maxElementDepth: JAXP00010006
• EntityReplacementLimit: JAXP00010007
The error code has the following format:
The code JAXP00010001, therefore, represents the JAXP base parser security limit
EntityExpansionLimit.
If access to external resources is denied due to the restrictions set by EAPs, then an exception
will be thrown with an error in the following format:
[Link](
"[Link] "file");
• Your application tries to fetch an external DTD with the HTTP protocol.
• The parser parsed an XML file that contains an external reference to http://
[Link]/dtd/[Link].
The error message would look like the following:
• Set up a local catalog and enable the Catalog API on all XML processors to further reduce
your applications' reliance on external resources.
Term Definition
JAXP Java API for XML Processing
Java SE XML API APIs defined in the JAXP JSR and integrated into
Java SE
Java XML API Equivalent term for Java SE XML API
Java XML Features and Properties XML-related features and properties defined by the
Java SE specification
[Link] The [Link] module
JDK XML The JDK implementation of the Java XML API
JDK XML Parsers The JDK implementation of the XML parsers
JDK XML Properties The JDK Implementation-only properties
EAPs External Access Properties
FSP The FEATURE_SECURE_PROCESSING Security
Directive
The JDK XML properties are JDK implementation-only properties. The prefix of the properties
is [Link] for JDK 8 and earlier and [Link] for JDK 9 and later. The
following table summarizes this naming convention:
Table 12-19 Java and JDK XML Features and Properties Naming Convention
Scope API Property Prefix System Property Prefix Java SE and JDK
Version
Java SE http:// [Link] Since 1.4
[Link]
nts/feature
http://
[Link]
nts/property
JDK http:// [Link] Since 7
[Link]/xml/
jaxp/properties
Table 12-19 (Cont.) Java and JDK XML Features and Properties Naming Convention
Scope API Property Prefix System Property Prefix Java SE and JDK
Version
JDK [Link] [Link] Since 9