feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
181
jdkSrc/jdk8/sun/security/acl/AclEntryImpl.java
Normal file
181
jdkSrc/jdk8/sun/security/acl/AclEntryImpl.java
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.acl;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.Principal;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* This is a class that describes one entry that associates users
|
||||
* or groups with permissions in the ACL.
|
||||
* The entry may be used as a way of granting or denying permissions.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class AclEntryImpl implements AclEntry {
|
||||
private Principal user = null;
|
||||
private Vector<Permission> permissionSet = new Vector<>(10, 10);
|
||||
private boolean negative = false;
|
||||
|
||||
/**
|
||||
* Construct an ACL entry that associates a user with permissions
|
||||
* in the ACL.
|
||||
* @param user The user that is associated with this entry.
|
||||
*/
|
||||
public AclEntryImpl(Principal user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a null ACL entry
|
||||
*/
|
||||
public AclEntryImpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the principal in the entity. If a group or a
|
||||
* principal had already been set, a false value is
|
||||
* returned, otherwise a true value is returned.
|
||||
* @param user The user that is associated with this entry.
|
||||
* @return true if the principal is set, false if there is
|
||||
* one already.
|
||||
*/
|
||||
public boolean setPrincipal(Principal user) {
|
||||
if (this.user != null)
|
||||
return false;
|
||||
this.user = user;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the ACL to have negative permissions.
|
||||
* That is the user or group is denied the permission set
|
||||
* specified in the entry.
|
||||
*/
|
||||
public void setNegativePermissions() {
|
||||
negative = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a negative ACL.
|
||||
*/
|
||||
public boolean isNegative() {
|
||||
return negative;
|
||||
}
|
||||
|
||||
/**
|
||||
* A principal or a group can be associated with multiple
|
||||
* permissions. This method adds a permission to the ACL entry.
|
||||
* @param permission The permission to be associated with
|
||||
* the principal or the group in the entry.
|
||||
* @return true if the permission was added, false if the
|
||||
* permission was already part of the permission set.
|
||||
*/
|
||||
public boolean addPermission(Permission permission) {
|
||||
|
||||
if (permissionSet.contains(permission))
|
||||
return false;
|
||||
|
||||
permissionSet.addElement(permission);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method disassociates the permission from the Principal
|
||||
* or the Group in this ACL entry.
|
||||
* @param permission The permission to be disassociated with
|
||||
* the principal or the group in the entry.
|
||||
* @return true if the permission is removed, false if the
|
||||
* permission is not part of the permission set.
|
||||
*/
|
||||
public boolean removePermission(Permission permission) {
|
||||
return permissionSet.removeElement(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed permission is part of the allowed
|
||||
* permission set in this entry.
|
||||
* @param permission The permission that has to be part of
|
||||
* the permission set in the entry.
|
||||
* @return true if the permission passed is part of the
|
||||
* permission set in the entry, false otherwise.
|
||||
*/
|
||||
public boolean checkPermission(Permission permission) {
|
||||
return permissionSet.contains(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* return an enumeration of the permissions in this ACL entry.
|
||||
*/
|
||||
public Enumeration<Permission> permissions() {
|
||||
return permissionSet.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the contents of the ACL entry.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer s = new StringBuffer();
|
||||
if (negative)
|
||||
s.append("-");
|
||||
else
|
||||
s.append("+");
|
||||
if (user instanceof Group)
|
||||
s.append("Group.");
|
||||
else
|
||||
s.append("User.");
|
||||
s.append(user + "=");
|
||||
Enumeration<Permission> e = permissions();
|
||||
while(e.hasMoreElements()) {
|
||||
Permission p = e.nextElement();
|
||||
s.append(p);
|
||||
if (e.hasMoreElements())
|
||||
s.append(",");
|
||||
}
|
||||
return new String(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones an AclEntry.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
|
||||
public synchronized Object clone() {
|
||||
AclEntryImpl cloned;
|
||||
cloned = new AclEntryImpl(user);
|
||||
cloned.permissionSet = (Vector<Permission>) permissionSet.clone();
|
||||
cloned.negative = negative;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Principal associated in this ACL entry.
|
||||
* The method returns null if the entry uses a group
|
||||
* instead of a principal.
|
||||
*/
|
||||
public Principal getPrincipal() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
408
jdkSrc/jdk8/sun/security/acl/AclImpl.java
Normal file
408
jdkSrc/jdk8/sun/security/acl/AclImpl.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.security.Principal;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* An Access Control List (ACL) is encapsulated by this class.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class AclImpl extends OwnerImpl implements Acl {
|
||||
//
|
||||
// Maintain four tables. one each for positive and negative
|
||||
// ACLs. One each depending on whether the entity is a group
|
||||
// or principal.
|
||||
//
|
||||
private Hashtable<Principal, AclEntry> allowedUsersTable =
|
||||
new Hashtable<>(23);
|
||||
private Hashtable<Principal, AclEntry> allowedGroupsTable =
|
||||
new Hashtable<>(23);
|
||||
private Hashtable<Principal, AclEntry> deniedUsersTable =
|
||||
new Hashtable<>(23);
|
||||
private Hashtable<Principal, AclEntry> deniedGroupsTable =
|
||||
new Hashtable<>(23);
|
||||
private String aclName = null;
|
||||
private Vector<Permission> zeroSet = new Vector<>(1,1);
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for creating an empty ACL.
|
||||
*/
|
||||
public AclImpl(Principal owner, String name) {
|
||||
super(owner);
|
||||
try {
|
||||
setName(owner, name);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the ACL.
|
||||
* @param caller the principal who is invoking this method.
|
||||
* @param name the name of the ACL.
|
||||
* @exception NotOwnerException if the caller principal is
|
||||
* not on the owners list of the Acl.
|
||||
*/
|
||||
public void setName(Principal caller, String name)
|
||||
throws NotOwnerException
|
||||
{
|
||||
if (!isOwner(caller))
|
||||
throw new NotOwnerException();
|
||||
|
||||
aclName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the ACL.
|
||||
* @return the name of the ACL.
|
||||
*/
|
||||
public String getName() {
|
||||
return aclName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an ACL entry to this ACL. An entry associates a
|
||||
* group or a principal with a set of permissions. Each
|
||||
* user or group can have one positive ACL entry and one
|
||||
* negative ACL entry. If there is one of the type (negative
|
||||
* or positive) already in the table, a false value is returned.
|
||||
* The caller principal must be a part of the owners list of
|
||||
* the ACL in order to invoke this method.
|
||||
* @param caller the principal who is invoking this method.
|
||||
* @param entry the ACL entry that must be added to the ACL.
|
||||
* @return true on success, false if the entry is already present.
|
||||
* @exception NotOwnerException if the caller principal
|
||||
* is not on the owners list of the Acl.
|
||||
*/
|
||||
public synchronized boolean addEntry(Principal caller, AclEntry entry)
|
||||
throws NotOwnerException
|
||||
{
|
||||
if (!isOwner(caller))
|
||||
throw new NotOwnerException();
|
||||
|
||||
Hashtable<Principal, AclEntry> aclTable = findTable(entry);
|
||||
Principal key = entry.getPrincipal();
|
||||
|
||||
if (aclTable.get(key) != null)
|
||||
return false;
|
||||
|
||||
aclTable.put(key, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an ACL entry from this ACL.
|
||||
* The caller principal must be a part of the owners list of the ACL
|
||||
* in order to invoke this method.
|
||||
* @param caller the principal who is invoking this method.
|
||||
* @param entry the ACL entry that must be removed from the ACL.
|
||||
* @return true on success, false if the entry is not part of the ACL.
|
||||
* @exception NotOwnerException if the caller principal is not
|
||||
* the owners list of the Acl.
|
||||
*/
|
||||
public synchronized boolean removeEntry(Principal caller, AclEntry entry)
|
||||
throws NotOwnerException
|
||||
{
|
||||
if (!isOwner(caller))
|
||||
throw new NotOwnerException();
|
||||
|
||||
Hashtable<Principal, AclEntry> aclTable = findTable(entry);
|
||||
Principal key = entry.getPrincipal();
|
||||
|
||||
AclEntry o = aclTable.remove(key);
|
||||
return (o != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the set of allowed permissions for the
|
||||
* specified principal. This set of allowed permissions is calculated
|
||||
* as follows:
|
||||
*
|
||||
* If there is no entry for a group or a principal an empty permission
|
||||
* set is assumed.
|
||||
*
|
||||
* The group positive permission set is the union of all
|
||||
* the positive permissions of each group that the individual belongs to.
|
||||
* The group negative permission set is the union of all
|
||||
* the negative permissions of each group that the individual belongs to.
|
||||
* If there is a specific permission that occurs in both
|
||||
* the postive permission set and the negative permission set,
|
||||
* it is removed from both. The group positive and negatoive permission
|
||||
* sets are calculated.
|
||||
*
|
||||
* The individial positive permission set and the individual negative
|
||||
* permission set is then calculated. Again abscence of an entry means
|
||||
* the empty set.
|
||||
*
|
||||
* The set of permissions granted to the principal is then calculated using
|
||||
* the simple rule: Individual permissions always override the Group permissions.
|
||||
* Specifically, individual negative permission set (specific
|
||||
* denial of permissions) overrides the group positive permission set.
|
||||
* And the individual positive permission set override the group negative
|
||||
* permission set.
|
||||
*
|
||||
* @param user the principal for which the ACL entry is returned.
|
||||
* @return The resulting permission set that the principal is allowed.
|
||||
*/
|
||||
public synchronized Enumeration<Permission> getPermissions(Principal user) {
|
||||
|
||||
Enumeration<Permission> individualPositive;
|
||||
Enumeration<Permission> individualNegative;
|
||||
Enumeration<Permission> groupPositive;
|
||||
Enumeration<Permission> groupNegative;
|
||||
|
||||
//
|
||||
// canonicalize the sets. That is remove common permissions from
|
||||
// positive and negative sets.
|
||||
//
|
||||
groupPositive =
|
||||
subtract(getGroupPositive(user), getGroupNegative(user));
|
||||
groupNegative =
|
||||
subtract(getGroupNegative(user), getGroupPositive(user));
|
||||
individualPositive =
|
||||
subtract(getIndividualPositive(user), getIndividualNegative(user));
|
||||
individualNegative =
|
||||
subtract(getIndividualNegative(user), getIndividualPositive(user));
|
||||
|
||||
//
|
||||
// net positive permissions is individual positive permissions
|
||||
// plus (group positive - individual negative).
|
||||
//
|
||||
Enumeration<Permission> temp1 =
|
||||
subtract(groupPositive, individualNegative);
|
||||
Enumeration<Permission> netPositive =
|
||||
union(individualPositive, temp1);
|
||||
|
||||
// recalculate the enumeration since we lost it in performing the
|
||||
// subtraction
|
||||
//
|
||||
individualPositive =
|
||||
subtract(getIndividualPositive(user), getIndividualNegative(user));
|
||||
individualNegative =
|
||||
subtract(getIndividualNegative(user), getIndividualPositive(user));
|
||||
|
||||
//
|
||||
// net negative permissions is individual negative permissions
|
||||
// plus (group negative - individual positive).
|
||||
//
|
||||
temp1 = subtract(groupNegative, individualPositive);
|
||||
Enumeration<Permission> netNegative = union(individualNegative, temp1);
|
||||
|
||||
return subtract(netPositive, netNegative);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether or not the specified principal
|
||||
* has the required permission. If permission is denied
|
||||
* permission false is returned, a true value is returned otherwise.
|
||||
* This method does not authenticate the principal. It presumes that
|
||||
* the principal is a valid authenticated principal.
|
||||
* @param principal the name of the authenticated principal
|
||||
* @param permission the permission that the principal must have.
|
||||
* @return true of the principal has the permission desired, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean checkPermission(Principal principal, Permission permission)
|
||||
{
|
||||
Enumeration<Permission> permSet = getPermissions(principal);
|
||||
while (permSet.hasMoreElements()) {
|
||||
Permission p = permSet.nextElement();
|
||||
if (p.equals(permission))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an enumeration of the entries in this ACL.
|
||||
*/
|
||||
public synchronized Enumeration<AclEntry> entries() {
|
||||
return new AclEnumerator(this,
|
||||
allowedUsersTable, allowedGroupsTable,
|
||||
deniedUsersTable, deniedGroupsTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a stringified version of the
|
||||
* ACL.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Enumeration<AclEntry> entries = entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
AclEntry entry = entries.nextElement();
|
||||
sb.append(entry.toString().trim());
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
//
|
||||
// Find the table that this entry belongs to. There are 4
|
||||
// tables that are maintained. One each for postive and
|
||||
// negative ACLs and one each for groups and users.
|
||||
// This method figures out which
|
||||
// table is the one that this AclEntry belongs to.
|
||||
//
|
||||
private Hashtable<Principal, AclEntry> findTable(AclEntry entry) {
|
||||
Hashtable<Principal, AclEntry> aclTable = null;
|
||||
|
||||
Principal p = entry.getPrincipal();
|
||||
if (p instanceof Group) {
|
||||
if (entry.isNegative())
|
||||
aclTable = deniedGroupsTable;
|
||||
else
|
||||
aclTable = allowedGroupsTable;
|
||||
} else {
|
||||
if (entry.isNegative())
|
||||
aclTable = deniedUsersTable;
|
||||
else
|
||||
aclTable = allowedUsersTable;
|
||||
}
|
||||
return aclTable;
|
||||
}
|
||||
|
||||
//
|
||||
// returns the set e1 U e2.
|
||||
//
|
||||
private static Enumeration<Permission> union(Enumeration<Permission> e1,
|
||||
Enumeration<Permission> e2) {
|
||||
Vector<Permission> v = new Vector<>(20, 20);
|
||||
|
||||
while (e1.hasMoreElements())
|
||||
v.addElement(e1.nextElement());
|
||||
|
||||
while (e2.hasMoreElements()) {
|
||||
Permission o = e2.nextElement();
|
||||
if (!v.contains(o))
|
||||
v.addElement(o);
|
||||
}
|
||||
|
||||
return v.elements();
|
||||
}
|
||||
|
||||
//
|
||||
// returns the set e1 - e2.
|
||||
//
|
||||
private Enumeration<Permission> subtract(Enumeration<Permission> e1,
|
||||
Enumeration<Permission> e2) {
|
||||
Vector<Permission> v = new Vector<>(20, 20);
|
||||
|
||||
while (e1.hasMoreElements())
|
||||
v.addElement(e1.nextElement());
|
||||
|
||||
while (e2.hasMoreElements()) {
|
||||
Permission o = e2.nextElement();
|
||||
if (v.contains(o))
|
||||
v.removeElement(o);
|
||||
}
|
||||
|
||||
return v.elements();
|
||||
}
|
||||
|
||||
private Enumeration<Permission> getGroupPositive(Principal user) {
|
||||
Enumeration<Permission> groupPositive = zeroSet.elements();
|
||||
Enumeration<Principal> e = allowedGroupsTable.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Group g = (Group)e.nextElement();
|
||||
if (g.isMember(user)) {
|
||||
AclEntry ae = allowedGroupsTable.get(g);
|
||||
groupPositive = union(ae.permissions(), groupPositive);
|
||||
}
|
||||
}
|
||||
return groupPositive;
|
||||
}
|
||||
|
||||
private Enumeration<Permission> getGroupNegative(Principal user) {
|
||||
Enumeration<Permission> groupNegative = zeroSet.elements();
|
||||
Enumeration<Principal> e = deniedGroupsTable.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Group g = (Group)e.nextElement();
|
||||
if (g.isMember(user)) {
|
||||
AclEntry ae = deniedGroupsTable.get(g);
|
||||
groupNegative = union(ae.permissions(), groupNegative);
|
||||
}
|
||||
}
|
||||
return groupNegative;
|
||||
}
|
||||
|
||||
private Enumeration<Permission> getIndividualPositive(Principal user) {
|
||||
Enumeration<Permission> individualPositive = zeroSet.elements();
|
||||
AclEntry ae = allowedUsersTable.get(user);
|
||||
if (ae != null)
|
||||
individualPositive = ae.permissions();
|
||||
return individualPositive;
|
||||
}
|
||||
|
||||
private Enumeration<Permission> getIndividualNegative(Principal user) {
|
||||
Enumeration<Permission> individualNegative = zeroSet.elements();
|
||||
AclEntry ae = deniedUsersTable.get(user);
|
||||
if (ae != null)
|
||||
individualNegative = ae.permissions();
|
||||
return individualNegative;
|
||||
}
|
||||
}
|
||||
|
||||
final class AclEnumerator implements Enumeration<AclEntry> {
|
||||
Acl acl;
|
||||
Enumeration<AclEntry> u1, u2, g1, g2;
|
||||
|
||||
AclEnumerator(Acl acl, Hashtable<?,AclEntry> u1, Hashtable<?,AclEntry> g1,
|
||||
Hashtable<?,AclEntry> u2, Hashtable<?,AclEntry> g2) {
|
||||
this.acl = acl;
|
||||
this.u1 = u1.elements();
|
||||
this.u2 = u2.elements();
|
||||
this.g1 = g1.elements();
|
||||
this.g2 = g2.elements();
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return (u1.hasMoreElements() ||
|
||||
u2.hasMoreElements() ||
|
||||
g1.hasMoreElements() ||
|
||||
g2.hasMoreElements());
|
||||
}
|
||||
|
||||
public AclEntry nextElement()
|
||||
{
|
||||
AclEntry o;
|
||||
synchronized (acl) {
|
||||
if (u1.hasMoreElements())
|
||||
return u1.nextElement();
|
||||
if (u2.hasMoreElements())
|
||||
return u2.nextElement();
|
||||
if (g1.hasMoreElements())
|
||||
return g1.nextElement();
|
||||
if (g2.hasMoreElements())
|
||||
return g2.nextElement();
|
||||
}
|
||||
throw new NoSuchElementException("Acl Enumerator");
|
||||
}
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/security/acl/AllPermissionsImpl.java
Normal file
50
jdkSrc/jdk8/sun/security/acl/AllPermissionsImpl.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1997, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* This class implements the principal interface for the set of all permissions.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class AllPermissionsImpl extends PermissionImpl {
|
||||
|
||||
public AllPermissionsImpl(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the permission passed matches the permission represented in
|
||||
* this interface.
|
||||
* @param another The Permission object to compare with.
|
||||
* @returns true always
|
||||
*/
|
||||
public boolean equals(Permission another) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
186
jdkSrc/jdk8/sun/security/acl/GroupImpl.java
Normal file
186
jdkSrc/jdk8/sun/security/acl/GroupImpl.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* This class implements a group of principals.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class GroupImpl implements Group {
|
||||
private Vector<Principal> groupMembers = new Vector<>(50, 100);
|
||||
private String group;
|
||||
|
||||
/**
|
||||
* Constructs a Group object with no members.
|
||||
* @param groupName the name of the group
|
||||
*/
|
||||
public GroupImpl(String groupName) {
|
||||
this.group = groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the specified member to the group.
|
||||
* @param user The principal to add to the group.
|
||||
* @return true if the member was added - false if the
|
||||
* member could not be added.
|
||||
*/
|
||||
public boolean addMember(Principal user) {
|
||||
if (groupMembers.contains(user))
|
||||
return false;
|
||||
|
||||
// do not allow groups to be added to itself.
|
||||
if (group.equals(user.toString()))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
groupMembers.addElement(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the specified member from the group.
|
||||
* @param user The principal to remove from the group.
|
||||
* @param true if the principal was removed false if
|
||||
* the principal was not a member
|
||||
*/
|
||||
public boolean removeMember(Principal user) {
|
||||
return groupMembers.removeElement(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the enumeration of the members in the group.
|
||||
*/
|
||||
public Enumeration<? extends Principal> members() {
|
||||
return groupMembers.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the group passed matches
|
||||
* the group represented in this interface.
|
||||
* @param another The group to compare this group to.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Group == false) {
|
||||
return false;
|
||||
}
|
||||
Group another = (Group)obj;
|
||||
return group.equals(another.toString());
|
||||
}
|
||||
|
||||
// equals(Group) for compatibility
|
||||
public boolean equals(Group another) {
|
||||
return equals((Object)another);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a stringified version of the group.
|
||||
*/
|
||||
public String toString() {
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a hashcode for the principal.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return group.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the passed principal is a member of the group.
|
||||
* @param member The principal whose membership must be checked for.
|
||||
* @return true if the principal is a member of this group,
|
||||
* false otherwise
|
||||
*/
|
||||
public boolean isMember(Principal member) {
|
||||
|
||||
//
|
||||
// if the member is part of the group (common case), return true.
|
||||
// if not, recursively search depth first in the group looking for the
|
||||
// principal.
|
||||
//
|
||||
if (groupMembers.contains(member)) {
|
||||
return true;
|
||||
} else {
|
||||
Vector<Group> alreadySeen = new Vector<>(10);
|
||||
return isMemberRecurse(member, alreadySeen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the name of the principal.
|
||||
*/
|
||||
public String getName() {
|
||||
return group;
|
||||
}
|
||||
|
||||
//
|
||||
// This function is the recursive search of groups for this
|
||||
// implementation of the Group. The search proceeds building up
|
||||
// a vector of already seen groups. Only new groups are considered,
|
||||
// thereby avoiding loops.
|
||||
//
|
||||
boolean isMemberRecurse(Principal member, Vector<Group> alreadySeen) {
|
||||
Enumeration<? extends Principal> e = members();
|
||||
while (e.hasMoreElements()) {
|
||||
boolean mem = false;
|
||||
Principal p = (Principal) e.nextElement();
|
||||
|
||||
// if the member is in this collection, return true
|
||||
if (p.equals(member)) {
|
||||
return true;
|
||||
} else if (p instanceof GroupImpl) {
|
||||
//
|
||||
// if not recurse if the group has not been checked already.
|
||||
// Can call method in this package only if the object is an
|
||||
// instance of this class. Otherwise call the method defined
|
||||
// in the interface. (This can lead to a loop if a mixture of
|
||||
// implementations form a loop, but we live with this improbable
|
||||
// case rather than clutter the interface by forcing the
|
||||
// implementation of this method.)
|
||||
//
|
||||
GroupImpl g = (GroupImpl) p;
|
||||
alreadySeen.addElement(this);
|
||||
if (!alreadySeen.contains(g))
|
||||
mem = g.isMemberRecurse(member, alreadySeen);
|
||||
} else if (p instanceof Group) {
|
||||
Group g = (Group) p;
|
||||
if (!alreadySeen.contains(g))
|
||||
mem = g.isMember(member);
|
||||
}
|
||||
|
||||
if (mem)
|
||||
return mem;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/security/acl/OwnerImpl.java
Normal file
108
jdkSrc/jdk8/sun/security/acl/OwnerImpl.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* Class implementing the Owner interface. The
|
||||
* initial owner principal is configured as
|
||||
* part of the constructor.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class OwnerImpl implements Owner {
|
||||
private Group ownerGroup;
|
||||
|
||||
public OwnerImpl(Principal owner) {
|
||||
ownerGroup = new GroupImpl("AclOwners");
|
||||
ownerGroup.addMember(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an owner. Owners can modify ACL contents and can disassociate
|
||||
* ACLs from the objects they protect in the AclConfig interface.
|
||||
* The caller principal must be a part of the owners list of the ACL in
|
||||
* order to invoke this method. The initial owner is configured
|
||||
* at ACL construction time.
|
||||
* @param caller the principal who is invoking this method.
|
||||
* @param owner The owner that should be added to the owners list.
|
||||
* @return true if success, false if already an owner.
|
||||
* @exception NotOwnerException if the caller principal is not on
|
||||
* the owners list of the Acl.
|
||||
*/
|
||||
public synchronized boolean addOwner(Principal caller, Principal owner)
|
||||
throws NotOwnerException
|
||||
{
|
||||
if (!isOwner(caller))
|
||||
throw new NotOwnerException();
|
||||
|
||||
ownerGroup.addMember(owner);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete owner. If this is the last owner in the ACL, an exception is
|
||||
* raised.
|
||||
* The caller principal must be a part of the owners list of the ACL in
|
||||
* order to invoke this method.
|
||||
* @param caller the principal who is invoking this method.
|
||||
* @param owner The owner to be removed from the owners list.
|
||||
* @return true if the owner is removed, false if the owner is not part
|
||||
* of the owners list.
|
||||
* @exception NotOwnerException if the caller principal is not on
|
||||
* the owners list of the Acl.
|
||||
* @exception LastOwnerException if there is only one owner left in the group, then
|
||||
* deleteOwner would leave the ACL owner-less. This exception is raised in such a case.
|
||||
*/
|
||||
public synchronized boolean deleteOwner(Principal caller, Principal owner)
|
||||
throws NotOwnerException, LastOwnerException
|
||||
{
|
||||
if (!isOwner(caller))
|
||||
throw new NotOwnerException();
|
||||
|
||||
Enumeration<? extends Principal> e = ownerGroup.members();
|
||||
//
|
||||
// check if there is atleast 2 members left.
|
||||
//
|
||||
Object o = e.nextElement();
|
||||
if (e.hasMoreElements())
|
||||
return ownerGroup.removeMember(owner);
|
||||
else
|
||||
throw new LastOwnerException();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if the given principal belongs to the owner list.
|
||||
* @param owner The owner to check if part of the owners list
|
||||
* @return true if the passed principal is in the owner list, false if not.
|
||||
*/
|
||||
public synchronized boolean isOwner(Principal owner) {
|
||||
return ownerGroup.isMember(owner);
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/security/acl/PermissionImpl.java
Normal file
80
jdkSrc/jdk8/sun/security/acl/PermissionImpl.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.acl.*;
|
||||
|
||||
/**
|
||||
* The PermissionImpl class implements the permission
|
||||
* interface for permissions that are strings.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class PermissionImpl implements Permission {
|
||||
|
||||
private String permission;
|
||||
|
||||
/**
|
||||
* Construct a permission object using a string.
|
||||
* @param permission the stringified version of the permission.
|
||||
*/
|
||||
public PermissionImpl(String permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the object passed matches the permission
|
||||
* represented in this interface.
|
||||
* @param another The Permission object to compare with.
|
||||
* @return true if the Permission objects are equal, false otherwise
|
||||
*/
|
||||
public boolean equals(Object another) {
|
||||
if (another instanceof Permission) {
|
||||
Permission p = (Permission) another;
|
||||
return permission.equals(p.toString());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a stringified version of the permission.
|
||||
* @return the string representation of the Permission.
|
||||
*/
|
||||
public String toString() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this PermissionImpl.
|
||||
*
|
||||
* @return a hashcode for this PermissionImpl.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
83
jdkSrc/jdk8/sun/security/acl/PrincipalImpl.java
Normal file
83
jdkSrc/jdk8/sun/security/acl/PrincipalImpl.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* This class implements the principal interface.
|
||||
*
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class PrincipalImpl implements Principal {
|
||||
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* Construct a principal from a string user name.
|
||||
* @param user The string form of the principal name.
|
||||
*/
|
||||
public PrincipalImpl(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the object passed matches
|
||||
* the principal represented in this implementation
|
||||
* @param another the Principal to compare with.
|
||||
* @return true if the Principal passed is the same as that
|
||||
* encapsulated in this object, false otherwise
|
||||
*/
|
||||
public boolean equals(Object another) {
|
||||
if (another instanceof PrincipalImpl) {
|
||||
PrincipalImpl p = (PrincipalImpl) another;
|
||||
return user.equals(p.toString());
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a stringified version of the principal.
|
||||
*/
|
||||
public String toString() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a hashcode for the principal.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return user.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the name of the principal.
|
||||
*/
|
||||
public String getName() {
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
48
jdkSrc/jdk8/sun/security/acl/WorldGroupImpl.java
Normal file
48
jdkSrc/jdk8/sun/security/acl/WorldGroupImpl.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.acl;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* This class implements a group of principals.
|
||||
* @author Satish Dharmaraj
|
||||
*/
|
||||
public class WorldGroupImpl extends GroupImpl {
|
||||
|
||||
public WorldGroupImpl(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true for all passed principals
|
||||
* @param member The principal whose membership must be checked in this Group.
|
||||
* @return true always since this is the "world" group.
|
||||
*/
|
||||
public boolean isMember(Principal member) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
72
jdkSrc/jdk8/sun/security/action/GetBooleanAction.java
Normal file
72
jdkSrc/jdk8/sun/security/action/GetBooleanAction.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the boolean value of a system property
|
||||
* as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the boolean value of the system
|
||||
* property named <code>"prop"</code> as a privileged action: <p>
|
||||
*
|
||||
* <pre>
|
||||
* boolean b = java.security.AccessController.doPrivileged
|
||||
* (new GetBooleanAction("prop")).booleanValue();
|
||||
* </pre>
|
||||
*
|
||||
* @author Roland Schemers
|
||||
* @see java.security.PrivilegedAction
|
||||
* @see java.security.AccessController
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class GetBooleanAction
|
||||
implements java.security.PrivilegedAction<Boolean> {
|
||||
private String theProp;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property whose boolean
|
||||
* value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
*/
|
||||
public GetBooleanAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the boolean value of the system property whose name was
|
||||
* specified in the constructor.
|
||||
*
|
||||
* @return the <code>Boolean</code> value of the system property.
|
||||
*/
|
||||
public Boolean run() {
|
||||
return Boolean.getBoolean(theProp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the boolean value of a security property
|
||||
* as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the boolean value of the security
|
||||
* property named <code>"prop"</code> as a privileged action: <p>
|
||||
*
|
||||
* <pre>
|
||||
* boolean b = java.security.AccessController.doPrivileged
|
||||
* (new GetBooleanSecurityPropertyAction("prop")).booleanValue();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class GetBooleanSecurityPropertyAction
|
||||
implements java.security.PrivilegedAction<Boolean> {
|
||||
private String theProp;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the security property whose boolean
|
||||
* value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the security property
|
||||
*/
|
||||
public GetBooleanSecurityPropertyAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the boolean value of the security property whose name was
|
||||
* specified in the constructor.
|
||||
*
|
||||
* @return the <code>Boolean</code> value of the security property.
|
||||
*/
|
||||
public Boolean run() {
|
||||
boolean b = false;
|
||||
try {
|
||||
String value = Security.getProperty(theProp);
|
||||
b = (value != null) && value.equalsIgnoreCase("true");
|
||||
} catch (NullPointerException e) {}
|
||||
return b;
|
||||
}
|
||||
}
|
||||
113
jdkSrc/jdk8/sun/security/action/GetIntegerAction.java
Normal file
113
jdkSrc/jdk8/sun/security/action/GetIntegerAction.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the integer value of a system property
|
||||
* as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the integer value of the system
|
||||
* property named <code>"prop"</code> as a privileged action. Since it does
|
||||
* not pass a default value to be used in case the property
|
||||
* <code>"prop"</code> is not defined, it has to check the result for
|
||||
* <code>null</code>: <p>
|
||||
*
|
||||
* <pre>
|
||||
* Integer tmp = java.security.AccessController.doPrivileged
|
||||
* (new sun.security.action.GetIntegerAction("prop"));
|
||||
* int i;
|
||||
* if (tmp != null) {
|
||||
* i = tmp.intValue();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The following code retrieves the integer value of the system
|
||||
* property named <code>"prop"</code> as a privileged action, and also passes
|
||||
* a default value to be used in case the property <code>"prop"</code> is not
|
||||
* defined: <p>
|
||||
*
|
||||
* <pre>
|
||||
* int i = ((Integer)java.security.AccessController.doPrivileged(
|
||||
* new GetIntegerAction("prop", 3))).intValue();
|
||||
* </pre>
|
||||
*
|
||||
* @author Roland Schemers
|
||||
* @see java.security.PrivilegedAction
|
||||
* @see java.security.AccessController
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class GetIntegerAction
|
||||
implements java.security.PrivilegedAction<Integer> {
|
||||
private String theProp;
|
||||
private int defaultVal;
|
||||
private boolean defaultSet = false;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property whose integer
|
||||
* value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
*/
|
||||
public GetIntegerAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property and the default
|
||||
* value of that property.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
* @param defaulVal the default value.
|
||||
*/
|
||||
public GetIntegerAction(String theProp, int defaultVal) {
|
||||
this.theProp = theProp;
|
||||
this.defaultVal = defaultVal;
|
||||
this.defaultSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the integer value of the system property whose name was
|
||||
* specified in the constructor.
|
||||
*
|
||||
* <p>If there is no property of the specified name, or if the property
|
||||
* does not have the correct numeric format, then an <code>Integer</code>
|
||||
* object representing the default value that was specified in the
|
||||
* constructor is returned, or <code>null</code> if no default value was
|
||||
* specified.
|
||||
*
|
||||
* @return the <code>Integer</code> value of the property.
|
||||
*/
|
||||
public Integer run() {
|
||||
Integer value = Integer.getInteger(theProp);
|
||||
if ((value == null) && defaultSet)
|
||||
return new Integer(defaultVal);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
112
jdkSrc/jdk8/sun/security/action/GetLongAction.java
Normal file
112
jdkSrc/jdk8/sun/security/action/GetLongAction.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the <code>Long</code> value of a system
|
||||
* property as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the <code>Long</code> value of the system
|
||||
* property named <code>"prop"</code> as a privileged action. Since it does
|
||||
* not pass a default value to be used in case the property
|
||||
* <code>"prop"</code> is not defined, it has to check the result for
|
||||
* <code>null</code>: <p>
|
||||
*
|
||||
* <pre>
|
||||
* Long tmp = java.security.AccessController.doPrivileged
|
||||
* (new sun.security.action.GetLongAction("prop"));
|
||||
* long l;
|
||||
* if (tmp != null) {
|
||||
* l = tmp.longValue();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The following code retrieves the <code>Long</code> value of the system
|
||||
* property named <code>"prop"</code> as a privileged action, and also passes
|
||||
* a default value to be used in case the property <code>"prop"</code> is not
|
||||
* defined: <p>
|
||||
*
|
||||
* <pre>
|
||||
* long l = java.security.AccessController.doPrivileged
|
||||
* (new GetLongAction("prop")).longValue();
|
||||
* </pre>
|
||||
*
|
||||
* @author Roland Schemers
|
||||
* @see java.security.PrivilegedAction
|
||||
* @see java.security.AccessController
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class GetLongAction implements java.security.PrivilegedAction<Long> {
|
||||
private String theProp;
|
||||
private long defaultVal;
|
||||
private boolean defaultSet = false;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property whose
|
||||
* <code>Long</code> value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
*/
|
||||
public GetLongAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property and the default
|
||||
* value of that property.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
* @param defaulVal the default value.
|
||||
*/
|
||||
public GetLongAction(String theProp, long defaultVal) {
|
||||
this.theProp = theProp;
|
||||
this.defaultVal = defaultVal;
|
||||
this.defaultSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the <code>Long</code> value of the system property whose
|
||||
* name was specified in the constructor.
|
||||
*
|
||||
* <p>If there is no property of the specified name, or if the property
|
||||
* does not have the correct numeric format, then a <code>Long</code>
|
||||
* object representing the default value that was specified in the
|
||||
* constructor is returned, or <code>null</code> if no default value was
|
||||
* specified.
|
||||
*
|
||||
* @return the <code>Long</code> value of the property.
|
||||
*/
|
||||
public Long run() {
|
||||
Long value = Long.getLong(theProp);
|
||||
if ((value == null) && defaultSet)
|
||||
return new Long(defaultVal);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
134
jdkSrc/jdk8/sun/security/action/GetPropertyAction.java
Normal file
134
jdkSrc/jdk8/sun/security/action/GetPropertyAction.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the string value of a system
|
||||
* property as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the value of the system
|
||||
* property named <code>"prop"</code> as a privileged action: <p>
|
||||
*
|
||||
* <pre>
|
||||
* String s = java.security.AccessController.doPrivileged
|
||||
* (new GetPropertyAction("prop"));
|
||||
* </pre>
|
||||
*
|
||||
* @author Roland Schemers
|
||||
* @see java.security.PrivilegedAction
|
||||
* @see java.security.AccessController
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class GetPropertyAction implements PrivilegedAction<String> {
|
||||
private String theProp;
|
||||
private String defaultVal;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property whose
|
||||
* string value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
*/
|
||||
public GetPropertyAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the system property and the default
|
||||
* value of that property.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
* @param defaulVal the default value.
|
||||
*/
|
||||
public GetPropertyAction(String theProp, String defaultVal) {
|
||||
this.theProp = theProp;
|
||||
this.defaultVal = defaultVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the string value of the system property whose
|
||||
* name was specified in the constructor.
|
||||
*
|
||||
* @return the string value of the system property,
|
||||
* or the default value if there is no property with that key.
|
||||
*/
|
||||
public String run() {
|
||||
String value = System.getProperty(theProp);
|
||||
return (value == null) ? defaultVal : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a property without going through doPrivileged
|
||||
* if no security manager is present. This is unsafe for inclusion in a
|
||||
* public API but allowable here since this class is by default restricted
|
||||
* by the package.access security property.
|
||||
*
|
||||
* Note that this method performs a privileged action using caller-provided
|
||||
* inputs. The caller of this method should take care to ensure that the
|
||||
* inputs are not tainted and the returned property is not made accessible
|
||||
* to untrusted code if it contains sensitive information.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
*/
|
||||
public static String privilegedGetProperty(String theProp) {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return System.getProperty(theProp);
|
||||
} else {
|
||||
return AccessController.doPrivileged(
|
||||
new GetPropertyAction(theProp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a property without going through doPrivileged
|
||||
* if no security manager is present. This is unsafe for inclusion in a
|
||||
* public API but allowable here since this class is now encapsulated.
|
||||
*
|
||||
* Note that this method performs a privileged action using caller-provided
|
||||
* inputs. The caller of this method should take care to ensure that the
|
||||
* inputs are not tainted and the returned property is not made accessible
|
||||
* to untrusted code if it contains sensitive information.
|
||||
*
|
||||
* @param theProp the name of the system property.
|
||||
* @param defaultVal the default value.
|
||||
*/
|
||||
public static String privilegedGetProperty(String theProp,
|
||||
String defaultVal) {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return System.getProperty(theProp, defaultVal);
|
||||
} else {
|
||||
return AccessController.doPrivileged(
|
||||
new GetPropertyAction(theProp, defaultVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
|
||||
/**
|
||||
* A convenience class for opening a FileInputStream as a privileged action.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public class OpenFileInputStreamAction
|
||||
implements PrivilegedExceptionAction<FileInputStream> {
|
||||
|
||||
private final File file;
|
||||
|
||||
public OpenFileInputStreamAction(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public OpenFileInputStreamAction(String filename) {
|
||||
this.file = new File(filename);
|
||||
}
|
||||
|
||||
public FileInputStream run() throws Exception {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
}
|
||||
56
jdkSrc/jdk8/sun/security/action/PutAllAction.java
Normal file
56
jdkSrc/jdk8/sun/security/action/PutAllAction.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A convenience PrivilegedAction class for setting the properties of
|
||||
* a provider. See the SunRsaSign provider for a usage example.
|
||||
*
|
||||
* @see sun.security.rsa.SunRsaSign
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public class PutAllAction implements PrivilegedAction<Void> {
|
||||
|
||||
private final Provider provider;
|
||||
private final Map<?, ?> map;
|
||||
|
||||
public PutAllAction(Provider provider, Map<?, ?> map) {
|
||||
this.provider = provider;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public Void run() {
|
||||
provider.putAll(map);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
287
jdkSrc/jdk8/sun/security/ec/ECDHKeyAgreement.java
Normal file
287
jdkSrc/jdk8/sun/security/ec/ECDHKeyAgreement.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.math.*;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import sun.security.util.ArrayUtil;
|
||||
import sun.security.util.ECUtil;
|
||||
import sun.security.util.math.*;
|
||||
import sun.security.ec.point.*;
|
||||
|
||||
/**
|
||||
* KeyAgreement implementation for ECDH.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public final class ECDHKeyAgreement extends KeyAgreementSpi {
|
||||
|
||||
// private key, if initialized
|
||||
private ECPrivateKey privateKey;
|
||||
|
||||
// public key, non-null between doPhase() & generateSecret() only
|
||||
private ECPublicKey publicKey;
|
||||
|
||||
// length of the secret to be derived
|
||||
private int secretLen;
|
||||
|
||||
/**
|
||||
* Constructs a new ECDHKeyAgreement.
|
||||
*/
|
||||
public ECDHKeyAgreement() {
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected void engineInit(Key key, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
if (!(key instanceof PrivateKey)) {
|
||||
throw new InvalidKeyException
|
||||
("Key must be instance of PrivateKey");
|
||||
}
|
||||
privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key);
|
||||
publicKey = null;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected void engineInit(Key key, AlgorithmParameterSpec params,
|
||||
SecureRandom random) throws InvalidKeyException,
|
||||
InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
}
|
||||
engineInit(key, random);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected Key engineDoPhase(Key key, boolean lastPhase)
|
||||
throws InvalidKeyException, IllegalStateException {
|
||||
if (privateKey == null) {
|
||||
throw new IllegalStateException("Not initialized");
|
||||
}
|
||||
if (publicKey != null) {
|
||||
throw new IllegalStateException("Phase already executed");
|
||||
}
|
||||
if (!lastPhase) {
|
||||
throw new IllegalStateException
|
||||
("Only two party agreement supported, lastPhase must be true");
|
||||
}
|
||||
if (!(key instanceof ECPublicKey)) {
|
||||
throw new InvalidKeyException
|
||||
("Key must be a PublicKey with algorithm EC");
|
||||
}
|
||||
|
||||
this.publicKey = (ECPublicKey) key;
|
||||
|
||||
ECParameterSpec params = publicKey.getParams();
|
||||
int keyLenBits = params.getCurve().getField().getFieldSize();
|
||||
secretLen = (keyLenBits + 7) >> 3;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void validateCoordinate(BigInteger c, BigInteger mod) {
|
||||
if (c.compareTo(BigInteger.ZERO) < 0) {
|
||||
throw new ProviderException("invalid coordinate");
|
||||
}
|
||||
|
||||
if (c.compareTo(mod) >= 0) {
|
||||
throw new ProviderException("invalid coordinate");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a public key is valid. Throw ProviderException
|
||||
* if it is not valid or could not be validated.
|
||||
*/
|
||||
private static void validate(ECOperations ops, ECPublicKey key) {
|
||||
|
||||
// ensure that integers are in proper range
|
||||
BigInteger x = key.getW().getAffineX();
|
||||
BigInteger y = key.getW().getAffineY();
|
||||
|
||||
BigInteger p = ops.getField().getSize();
|
||||
validateCoordinate(x, p);
|
||||
validateCoordinate(y, p);
|
||||
|
||||
// ensure the point is on the curve
|
||||
EllipticCurve curve = key.getParams().getCurve();
|
||||
BigInteger rhs = x.modPow(BigInteger.valueOf(3), p).add(curve.getA()
|
||||
.multiply(x)).add(curve.getB()).mod(p);
|
||||
BigInteger lhs = y.modPow(BigInteger.valueOf(2), p).mod(p);
|
||||
if (!rhs.equals(lhs)) {
|
||||
throw new ProviderException("point is not on curve");
|
||||
}
|
||||
|
||||
// check the order of the point
|
||||
ImmutableIntegerModuloP xElem = ops.getField().getElement(x);
|
||||
ImmutableIntegerModuloP yElem = ops.getField().getElement(y);
|
||||
AffinePoint affP = new AffinePoint(xElem, yElem);
|
||||
byte[] order = key.getParams().getOrder().toByteArray();
|
||||
ArrayUtil.reverse(order);
|
||||
Point product = ops.multiply(affP, order);
|
||||
if (!ops.isNeutral(product)) {
|
||||
throw new ProviderException("point has incorrect order");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected byte[] engineGenerateSecret() throws IllegalStateException {
|
||||
if ((privateKey == null) || (publicKey == null)) {
|
||||
throw new IllegalStateException("Not initialized correctly");
|
||||
}
|
||||
|
||||
Optional<byte[]> resultOpt = deriveKeyImpl(privateKey, publicKey);
|
||||
return resultOpt.orElseGet(
|
||||
() -> deriveKeyNative(privateKey, publicKey)
|
||||
);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineGenerateSecret(byte[] sharedSecret, int
|
||||
offset) throws IllegalStateException, ShortBufferException {
|
||||
if (offset + secretLen > sharedSecret.length) {
|
||||
throw new ShortBufferException("Need " + secretLen
|
||||
+ " bytes, only " + (sharedSecret.length - offset)
|
||||
+ " available");
|
||||
}
|
||||
byte[] secret = engineGenerateSecret();
|
||||
System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
|
||||
return secret.length;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected SecretKey engineGenerateSecret(String algorithm)
|
||||
throws IllegalStateException, NoSuchAlgorithmException,
|
||||
InvalidKeyException {
|
||||
if (algorithm == null) {
|
||||
throw new NoSuchAlgorithmException("Algorithm must not be null");
|
||||
}
|
||||
if (!(algorithm.equals("TlsPremasterSecret"))) {
|
||||
throw new NoSuchAlgorithmException
|
||||
("Only supported for algorithm TlsPremasterSecret");
|
||||
}
|
||||
return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
|
||||
}
|
||||
|
||||
private static
|
||||
Optional<byte[]> deriveKeyImpl(ECPrivateKey priv, ECPublicKey pubKey) {
|
||||
|
||||
ECParameterSpec ecSpec = priv.getParams();
|
||||
EllipticCurve curve = ecSpec.getCurve();
|
||||
Optional<ECOperations> opsOpt = ECOperations.forParameters(ecSpec);
|
||||
if (!opsOpt.isPresent()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ECOperations ops = opsOpt.get();
|
||||
if (! (priv instanceof ECPrivateKeyImpl)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) priv;
|
||||
byte[] sArr = privImpl.getArrayS();
|
||||
|
||||
// to match the native implementation, validate the public key here
|
||||
// and throw ProviderException if it is invalid
|
||||
validate(ops, pubKey);
|
||||
|
||||
IntegerFieldModuloP field = ops.getField();
|
||||
// convert s array into field element and multiply by the cofactor
|
||||
MutableIntegerModuloP scalar = field.getElement(sArr).mutable();
|
||||
SmallValue cofactor =
|
||||
field.getSmallValue(priv.getParams().getCofactor());
|
||||
scalar.setProduct(cofactor);
|
||||
int keySize = (curve.getField().getFieldSize() + 7) / 8;
|
||||
byte[] privArr = scalar.asByteArray(keySize);
|
||||
|
||||
ImmutableIntegerModuloP x =
|
||||
field.getElement(pubKey.getW().getAffineX());
|
||||
ImmutableIntegerModuloP y =
|
||||
field.getElement(pubKey.getW().getAffineY());
|
||||
AffinePoint affPub = new AffinePoint(x, y);
|
||||
Point product = ops.multiply(affPub, privArr);
|
||||
if (ops.isNeutral(product)) {
|
||||
throw new ProviderException("Product is zero");
|
||||
}
|
||||
AffinePoint affProduct = product.asAffine();
|
||||
|
||||
byte[] result = affProduct.getX().asByteArray(keySize);
|
||||
ArrayUtil.reverse(result);
|
||||
|
||||
return Optional.of(result);
|
||||
}
|
||||
|
||||
private static
|
||||
byte[] deriveKeyNative(ECPrivateKey privateKey, ECPublicKey publicKey) {
|
||||
|
||||
ECParameterSpec params = privateKey.getParams();
|
||||
byte[] s = privateKey.getS().toByteArray();
|
||||
byte[] encodedParams = // DER OID
|
||||
ECUtil.encodeECParameterSpec(null, params);
|
||||
|
||||
byte[] publicValue;
|
||||
if (publicKey instanceof ECPublicKeyImpl) {
|
||||
ECPublicKeyImpl ecPub = (ECPublicKeyImpl) publicKey;
|
||||
publicValue = ecPub.getEncodedPublicValue();
|
||||
} else { // instanceof ECPublicKey
|
||||
publicValue =
|
||||
ECUtil.encodePoint(publicKey.getW(), params.getCurve());
|
||||
}
|
||||
|
||||
try {
|
||||
return deriveKey(s, publicValue, encodedParams);
|
||||
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ProviderException("Could not derive key", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a secret key using the public and private keys.
|
||||
*
|
||||
* @param s the private key's S value.
|
||||
* @param w the public key's W point (in uncompressed form).
|
||||
* @param encodedParams the curve's DER encoded object identifier.
|
||||
*
|
||||
* @return byte[] the secret key.
|
||||
*/
|
||||
private static native byte[] deriveKey(byte[] s, byte[] w,
|
||||
byte[] encodedParams) throws GeneralSecurityException;
|
||||
}
|
||||
202
jdkSrc/jdk8/sun/security/ec/ECDSAOperations.java
Normal file
202
jdkSrc/jdk8/sun/security/ec/ECDSAOperations.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import sun.security.ec.point.*;
|
||||
import sun.security.util.ArrayUtil;
|
||||
import sun.security.util.math.*;
|
||||
import static sun.security.ec.ECOperations.IntermediateValueException;
|
||||
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.*;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ECDSAOperations {
|
||||
|
||||
public static class Seed {
|
||||
private final byte[] seedValue;
|
||||
|
||||
public Seed(byte[] seedValue) {
|
||||
this.seedValue = seedValue;
|
||||
}
|
||||
|
||||
public byte[] getSeedValue() {
|
||||
return seedValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Nonce {
|
||||
private final byte[] nonceValue;
|
||||
|
||||
public Nonce(byte[] nonceValue) {
|
||||
this.nonceValue = nonceValue;
|
||||
}
|
||||
|
||||
public byte[] getNonceValue() {
|
||||
return nonceValue;
|
||||
}
|
||||
}
|
||||
|
||||
private final ECOperations ecOps;
|
||||
private final AffinePoint basePoint;
|
||||
|
||||
public ECDSAOperations(ECOperations ecOps, ECPoint basePoint) {
|
||||
this.ecOps = ecOps;
|
||||
this.basePoint = toAffinePoint(basePoint, ecOps.getField());
|
||||
}
|
||||
|
||||
public ECOperations getEcOperations() {
|
||||
return ecOps;
|
||||
}
|
||||
|
||||
public AffinePoint basePointMultiply(byte[] scalar) {
|
||||
return ecOps.multiply(basePoint, scalar).asAffine();
|
||||
}
|
||||
|
||||
public static AffinePoint toAffinePoint(ECPoint point,
|
||||
IntegerFieldModuloP field) {
|
||||
|
||||
ImmutableIntegerModuloP affineX = field.getElement(point.getAffineX());
|
||||
ImmutableIntegerModuloP affineY = field.getElement(point.getAffineY());
|
||||
return new AffinePoint(affineX, affineY);
|
||||
}
|
||||
|
||||
public static
|
||||
Optional<ECDSAOperations> forParameters(ECParameterSpec ecParams) {
|
||||
Optional<ECOperations> curveOps =
|
||||
ECOperations.forParameters(ecParams);
|
||||
return curveOps.map(
|
||||
ops -> new ECDSAOperations(ops, ecParams.getGenerator())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Sign a digest using the provided private key and seed.
|
||||
* IMPORTANT: The private key is a scalar represented using a
|
||||
* little-endian byte array. This is backwards from the conventional
|
||||
* representation in ECDSA. The routines that produce and consume this
|
||||
* value uses little-endian, so this deviation from convention removes
|
||||
* the requirement to swap the byte order. The returned signature is in
|
||||
* the conventional byte order.
|
||||
*
|
||||
* @param privateKey the private key scalar as a little-endian byte array
|
||||
* @param digest the digest to be signed
|
||||
* @param seed the seed that will be used to produce the nonce. This object
|
||||
* should contain an array that is at least 64 bits longer than
|
||||
* the number of bits required to represent the group order.
|
||||
* @return the ECDSA signature value
|
||||
* @throws IntermediateValueException if the signature cannot be produced
|
||||
* due to an unacceptable intermediate or final value. If this
|
||||
* exception is thrown, then the caller should discard the nonnce and
|
||||
* try again with an entirely new nonce value.
|
||||
*/
|
||||
public byte[] signDigest(byte[] privateKey, byte[] digest, Seed seed)
|
||||
throws IntermediateValueException {
|
||||
|
||||
byte[] nonceArr = ecOps.seedToScalar(seed.getSeedValue());
|
||||
|
||||
Nonce nonce = new Nonce(nonceArr);
|
||||
return signDigest(privateKey, digest, nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Sign a digest using the provided private key and nonce.
|
||||
* IMPORTANT: The private key and nonce are scalars represented by a
|
||||
* little-endian byte array. This is backwards from the conventional
|
||||
* representation in ECDSA. The routines that produce and consume these
|
||||
* values use little-endian, so this deviation from convention removes
|
||||
* the requirement to swap the byte order. The returned signature is in
|
||||
* the conventional byte order.
|
||||
*
|
||||
* @param privateKey the private key scalar as a little-endian byte array
|
||||
* @param digest the digest to be signed
|
||||
* @param nonce the nonce object containing a little-endian scalar value.
|
||||
* @return the ECDSA signature value
|
||||
* @throws IntermediateValueException if the signature cannot be produced
|
||||
* due to an unacceptable intermediate or final value. If this
|
||||
* exception is thrown, then the caller should discard the nonnce and
|
||||
* try again with an entirely new nonce value.
|
||||
*/
|
||||
public byte[] signDigest(byte[] privateKey, byte[] digest, Nonce nonce)
|
||||
throws IntermediateValueException {
|
||||
|
||||
IntegerFieldModuloP orderField = ecOps.getOrderField();
|
||||
int orderBits = orderField.getSize().bitLength();
|
||||
if (orderBits % 8 != 0 && orderBits < digest.length * 8) {
|
||||
// This implementation does not support truncating digests to
|
||||
// a length that is not a multiple of 8.
|
||||
throw new ProviderException("Invalid digest length");
|
||||
}
|
||||
|
||||
byte[] k = nonce.getNonceValue();
|
||||
// check nonce length
|
||||
int length = (orderField.getSize().bitLength() + 7) / 8;
|
||||
if (k.length != length) {
|
||||
throw new ProviderException("Incorrect nonce length");
|
||||
}
|
||||
|
||||
MutablePoint R = ecOps.multiply(basePoint, k);
|
||||
IntegerModuloP r = R.asAffine().getX();
|
||||
// put r into the correct field by fully reducing to an array
|
||||
byte[] temp = new byte[length];
|
||||
r.asByteArray(temp);
|
||||
r = orderField.getElement(temp);
|
||||
// store r in result
|
||||
r.asByteArray(temp);
|
||||
byte[] result = new byte[2 * length];
|
||||
ArrayUtil.reverse(temp);
|
||||
System.arraycopy(temp, 0, result, 0, length);
|
||||
// compare r to 0
|
||||
if (ECOperations.allZero(temp)) {
|
||||
throw new IntermediateValueException();
|
||||
}
|
||||
|
||||
IntegerModuloP dU = orderField.getElement(privateKey);
|
||||
int lengthE = Math.min(length, digest.length);
|
||||
byte[] E = new byte[lengthE];
|
||||
System.arraycopy(digest, 0, E, 0, lengthE);
|
||||
ArrayUtil.reverse(E);
|
||||
IntegerModuloP e = orderField.getElement(E);
|
||||
IntegerModuloP kElem = orderField.getElement(k);
|
||||
IntegerModuloP kInv = kElem.multiplicativeInverse();
|
||||
MutableIntegerModuloP s = r.mutable();
|
||||
s.setProduct(dU).setSum(e).setProduct(kInv);
|
||||
// store s in result
|
||||
s.asByteArray(temp);
|
||||
ArrayUtil.reverse(temp);
|
||||
System.arraycopy(temp, 0, result, length, length);
|
||||
// compare s to 0
|
||||
if (ECOperations.allZero(temp)) {
|
||||
throw new IntermediateValueException();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
498
jdkSrc/jdk8/sun/security/ec/ECDSASignature.java
Normal file
498
jdkSrc/jdk8/sun/security/ec/ECDSASignature.java
Normal file
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.Optional;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
import sun.security.util.*;
|
||||
import static sun.security.ec.ECOperations.IntermediateValueException;
|
||||
|
||||
/**
|
||||
* ECDSA signature implementation. This class currently supports the
|
||||
* following algorithm names:
|
||||
*
|
||||
* . "NONEwithECDSA"
|
||||
* . "SHA1withECDSA"
|
||||
* . "SHA224withECDSA"
|
||||
* . "SHA256withECDSA"
|
||||
* . "SHA384withECDSA"
|
||||
* . "SHA512withECDSA"
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
abstract class ECDSASignature extends SignatureSpi {
|
||||
|
||||
// message digest implementation we use
|
||||
private final MessageDigest messageDigest;
|
||||
|
||||
// supplied entropy
|
||||
private SecureRandom random;
|
||||
|
||||
// flag indicating whether the digest has been reset
|
||||
private boolean needsReset;
|
||||
|
||||
// private key, if initialized for signing
|
||||
private ECPrivateKey privateKey;
|
||||
|
||||
// public key, if initialized for verifying
|
||||
private ECPublicKey publicKey;
|
||||
|
||||
// signature parameters
|
||||
private ECParameterSpec sigParams = null;
|
||||
|
||||
/**
|
||||
* Constructs a new ECDSASignature. Used by Raw subclass.
|
||||
*
|
||||
* @exception ProviderException if the native ECC library is unavailable.
|
||||
*/
|
||||
ECDSASignature() {
|
||||
messageDigest = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ECDSASignature. Used by subclasses.
|
||||
*/
|
||||
ECDSASignature(String digestName) {
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance(digestName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
needsReset = false;
|
||||
}
|
||||
|
||||
// Nested class for NONEwithECDSA signatures
|
||||
public static final class Raw extends ECDSASignature {
|
||||
|
||||
// the longest supported digest is 512 bits (SHA-512)
|
||||
private static final int RAW_ECDSA_MAX = 64;
|
||||
|
||||
private final byte[] precomputedDigest;
|
||||
private int offset = 0;
|
||||
|
||||
public Raw() {
|
||||
precomputedDigest = new byte[RAW_ECDSA_MAX];
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
if (offset >= precomputedDigest.length) {
|
||||
offset = RAW_ECDSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
precomputedDigest[offset++] = b;
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
if (offset >= precomputedDigest.length) {
|
||||
offset = RAW_ECDSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
System.arraycopy(b, off, precomputedDigest, offset, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer byteBuffer) {
|
||||
int len = byteBuffer.remaining();
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
if (offset + len >= precomputedDigest.length) {
|
||||
offset = RAW_ECDSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
byteBuffer.get(precomputedDigest, offset, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetDigest() {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// Returns the precomputed message digest value.
|
||||
@Override
|
||||
protected byte[] getDigestValue() throws SignatureException {
|
||||
if (offset > RAW_ECDSA_MAX) {
|
||||
throw new SignatureException("Message digest is too long");
|
||||
|
||||
}
|
||||
byte[] result = new byte[offset];
|
||||
System.arraycopy(precomputedDigest, 0, result, 0, offset);
|
||||
offset = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA1withECDSA signatures
|
||||
public static final class SHA1 extends ECDSASignature {
|
||||
public SHA1() {
|
||||
super("SHA1");
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA224withECDSA signatures
|
||||
public static final class SHA224 extends ECDSASignature {
|
||||
public SHA224() {
|
||||
super("SHA-224");
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA256withECDSA signatures
|
||||
public static final class SHA256 extends ECDSASignature {
|
||||
public SHA256() {
|
||||
super("SHA-256");
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA384withECDSA signatures
|
||||
public static final class SHA384 extends ECDSASignature {
|
||||
public SHA384() {
|
||||
super("SHA-384");
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA512withECDSA signatures
|
||||
public static final class SHA512 extends ECDSASignature {
|
||||
public SHA512() {
|
||||
super("SHA-512");
|
||||
}
|
||||
}
|
||||
|
||||
// initialize for verification. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey publicKey)
|
||||
throws InvalidKeyException {
|
||||
ECPublicKey key = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
|
||||
if (!isCompatible(this.sigParams, key.getParams())) {
|
||||
throw new InvalidKeyException("Key params does not match signature params");
|
||||
}
|
||||
|
||||
// Should check that the supplied key is appropriate for signature
|
||||
// algorithm (e.g. P-256 for SHA256withECDSA)
|
||||
this.publicKey = key;
|
||||
this.privateKey = null;
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey)
|
||||
throws InvalidKeyException {
|
||||
engineInitSign(privateKey, null);
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
ECPrivateKey key = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
|
||||
if (!isCompatible(this.sigParams, key.getParams())) {
|
||||
throw new InvalidKeyException("Key params does not match signature params");
|
||||
}
|
||||
|
||||
// Should check that the supplied key is appropriate for signature
|
||||
// algorithm (e.g. P-256 for SHA256withECDSA)
|
||||
this.privateKey = key;
|
||||
this.publicKey = null;
|
||||
this.random = random;
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the message digest if needed.
|
||||
*/
|
||||
protected void resetDigest() {
|
||||
if (needsReset) {
|
||||
if (messageDigest != null) {
|
||||
messageDigest.reset();
|
||||
}
|
||||
needsReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message digest value.
|
||||
*/
|
||||
protected byte[] getDigestValue() throws SignatureException {
|
||||
needsReset = false;
|
||||
return messageDigest.digest();
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
messageDigest.update(b);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
messageDigest.update(b, off, len);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer byteBuffer) {
|
||||
int len = byteBuffer.remaining();
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageDigest.update(byteBuffer);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
private static boolean isCompatible(ECParameterSpec sigParams,
|
||||
ECParameterSpec keyParams) {
|
||||
if (sigParams == null) {
|
||||
// no restriction on key param
|
||||
return true;
|
||||
}
|
||||
return ECUtil.equals(sigParams, keyParams);
|
||||
}
|
||||
|
||||
|
||||
private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
|
||||
byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
|
||||
throws SignatureException {
|
||||
|
||||
byte[] seedBytes = new byte[(seedBits + 7) / 8];
|
||||
byte[] s = privImpl.getArrayS();
|
||||
|
||||
// Attempt to create the signature in a loop that uses new random input
|
||||
// each time. The chance of failure is very small assuming the
|
||||
// implementation derives the nonce using extra bits
|
||||
int numAttempts = 128;
|
||||
for (int i = 0; i < numAttempts; i++) {
|
||||
random.nextBytes(seedBytes);
|
||||
ECDSAOperations.Seed seed = new ECDSAOperations.Seed(seedBytes);
|
||||
try {
|
||||
return ops.signDigest(s, digest, seed);
|
||||
} catch (IntermediateValueException ex) {
|
||||
// try again in the next iteration
|
||||
}
|
||||
}
|
||||
|
||||
throw new SignatureException("Unable to produce signature after "
|
||||
+ numAttempts + " attempts");
|
||||
}
|
||||
|
||||
|
||||
private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,
|
||||
byte[] digest, SecureRandom random) throws SignatureException {
|
||||
|
||||
if (! (privateKey instanceof ECPrivateKeyImpl)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;
|
||||
ECParameterSpec params = privateKey.getParams();
|
||||
|
||||
// seed is the key size + 64 bits
|
||||
int seedBits = params.getOrder().bitLength() + 64;
|
||||
Optional<ECDSAOperations> opsOpt =
|
||||
ECDSAOperations.forParameters(params);
|
||||
if (!opsOpt.isPresent()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
|
||||
privImpl, random);
|
||||
return Optional.of(sig);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] signDigestNative(ECPrivateKey privateKey, byte[] digest,
|
||||
SecureRandom random) throws SignatureException {
|
||||
|
||||
byte[] s = privateKey.getS().toByteArray();
|
||||
ECParameterSpec params = privateKey.getParams();
|
||||
|
||||
// DER OID
|
||||
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
|
||||
int orderLength = params.getOrder().bitLength();
|
||||
|
||||
// seed is twice the order length (in bytes) plus 1
|
||||
byte[] seed = new byte[(((orderLength + 7) >> 3) + 1) * 2];
|
||||
|
||||
random.nextBytes(seed);
|
||||
|
||||
// random bits needed for timing countermeasures
|
||||
int timingArgument = random.nextInt();
|
||||
// values must be non-zero to enable countermeasures
|
||||
timingArgument |= 1;
|
||||
|
||||
try {
|
||||
return signDigest(digest, s, encodedParams, seed,
|
||||
timingArgument);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignatureException("Could not sign data", e);
|
||||
}
|
||||
}
|
||||
|
||||
// sign the data and return the signature. See JCA doc
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
|
||||
byte[] digest = getDigestValue();
|
||||
Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);
|
||||
byte[] sig;
|
||||
if (sigOpt.isPresent()) {
|
||||
sig = sigOpt.get();
|
||||
} else {
|
||||
sig = signDigestNative(privateKey, digest, random);
|
||||
}
|
||||
|
||||
return ECUtil.encodeSignature(sig);
|
||||
}
|
||||
|
||||
// verify the data and return the result. See JCA doc
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] signature) throws SignatureException {
|
||||
|
||||
byte[] w;
|
||||
ECParameterSpec params = publicKey.getParams();
|
||||
// DER OID
|
||||
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
|
||||
|
||||
if (publicKey instanceof ECPublicKeyImpl) {
|
||||
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
|
||||
} else { // instanceof ECPublicKey
|
||||
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return verifySignedDigest(
|
||||
ECUtil.decodeSignature(signature), getDigestValue(),
|
||||
w, encodedParams);
|
||||
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignatureException("Could not verify signature", e);
|
||||
}
|
||||
}
|
||||
|
||||
// set parameter, not supported. See JCA doc
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void engineSetParameter(String param, Object value)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("setParameter() not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (params != null && !(params instanceof ECParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException("No parameter accepted");
|
||||
}
|
||||
ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);
|
||||
if ((key != null) && !isCompatible((ECParameterSpec)params, key.getParams())) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Signature params does not match key params");
|
||||
}
|
||||
|
||||
sigParams = (ECParameterSpec) params;
|
||||
}
|
||||
|
||||
// get parameter, not supported. See JCA doc
|
||||
@Override
|
||||
@Deprecated
|
||||
protected Object engineGetParameter(String param)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("getParameter() not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
if (sigParams == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
|
||||
ap.init(sigParams);
|
||||
return ap;
|
||||
} catch (Exception e) {
|
||||
// should never happen
|
||||
throw new ProviderException("Error retrieving EC parameters", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the digest using the private key.
|
||||
*
|
||||
* @param digest the digest to be signed.
|
||||
* @param s the private key's S value.
|
||||
* @param encodedParams the curve's DER encoded object identifier.
|
||||
* @param seed the random seed.
|
||||
* @param timing When non-zero, the implmentation will use timing
|
||||
* countermeasures to hide secrets from timing channels. The EC
|
||||
* implementation will disable the countermeasures when this value is
|
||||
* zero, because the underlying EC functions are shared by several
|
||||
* crypto operations, some of which do not use the countermeasures.
|
||||
* The high-order 31 bits must be uniformly random. The entropy from
|
||||
* these bits is used by the countermeasures.
|
||||
*
|
||||
* @return byte[] the signature.
|
||||
*/
|
||||
private static native byte[] signDigest(byte[] digest, byte[] s,
|
||||
byte[] encodedParams, byte[] seed, int timing)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Verifies the signed digest using the public key.
|
||||
*
|
||||
* @param signature the signature to be verified. It is encoded
|
||||
* as a concatenation of the key's R and S values.
|
||||
* @param digest the digest to be used.
|
||||
* @param w the public key's W point (in uncompressed form).
|
||||
* @param encodedParams the curve's DER encoded object identifier.
|
||||
*
|
||||
* @return boolean true if the signature is successfully verified.
|
||||
*/
|
||||
private static native boolean verifySignedDigest(byte[] signature,
|
||||
byte[] digest, byte[] w, byte[] encodedParams)
|
||||
throws GeneralSecurityException;
|
||||
}
|
||||
290
jdkSrc/jdk8/sun/security/ec/ECKeyFactory.java
Normal file
290
jdkSrc/jdk8/sun/security/ec/ECKeyFactory.java
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
/**
|
||||
* KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
|
||||
* and getAlgorithm() must return "EC". For such keys, it supports conversion
|
||||
* between the following:
|
||||
*
|
||||
* For public keys:
|
||||
* . PublicKey with an X.509 encoding
|
||||
* . ECPublicKey
|
||||
* . ECPublicKeySpec
|
||||
* . X509EncodedKeySpec
|
||||
*
|
||||
* For private keys:
|
||||
* . PrivateKey with a PKCS#8 encoding
|
||||
* . ECPrivateKey
|
||||
* . ECPrivateKeySpec
|
||||
* . PKCS8EncodedKeySpec
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class ECKeyFactory extends KeyFactorySpi {
|
||||
|
||||
// Used by translateKey()
|
||||
private static KeyFactory instance;
|
||||
|
||||
private static KeyFactory getInstance() {
|
||||
if (instance == null) {
|
||||
try {
|
||||
instance = KeyFactory.getInstance("EC", "SunEC");
|
||||
} catch (NoSuchProviderException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ECKeyFactory() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to convert Key into a useable instance of
|
||||
* ECPublicKey or ECPrivateKey. Check the key and convert it
|
||||
* to a Sun key if necessary. If the key is not an EC key
|
||||
* or cannot be used, throw an InvalidKeyException.
|
||||
*
|
||||
* The difference between this method and engineTranslateKey() is that
|
||||
* we do not convert keys of other providers that are already an
|
||||
* instance of ECPublicKey or ECPrivateKey.
|
||||
*
|
||||
* To be used by future Java ECDSA and ECDH implementations.
|
||||
*/
|
||||
public static ECKey toECKey(Key key) throws InvalidKeyException {
|
||||
if (key instanceof ECKey) {
|
||||
ECKey ecKey = (ECKey)key;
|
||||
checkKey(ecKey);
|
||||
return ecKey;
|
||||
} else {
|
||||
/*
|
||||
* We don't call the engineTranslateKey method directly
|
||||
* because KeyFactory.translateKey adds code to loop through
|
||||
* all key factories.
|
||||
*/
|
||||
return (ECKey)getInstance().translateKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given EC key is valid.
|
||||
*/
|
||||
private static void checkKey(ECKey key) throws InvalidKeyException {
|
||||
// check for subinterfaces, omit additional checks for our keys
|
||||
if (key instanceof ECPublicKey) {
|
||||
if (key instanceof ECPublicKeyImpl) {
|
||||
return;
|
||||
}
|
||||
} else if (key instanceof ECPrivateKey) {
|
||||
if (key instanceof ECPrivateKeyImpl) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
throw new InvalidKeyException("Neither a public nor a private key");
|
||||
}
|
||||
// ECKey does not extend Key, so we need to do a cast
|
||||
String keyAlg = ((Key)key).getAlgorithm();
|
||||
if (keyAlg.equals("EC") == false) {
|
||||
throw new InvalidKeyException("Not an EC key: " + keyAlg);
|
||||
}
|
||||
// XXX further sanity checks about whether this key uses supported
|
||||
// fields, point formats, etc. would go here
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an EC key into a Sun EC key. If conversion is
|
||||
* not possible, throw an InvalidKeyException.
|
||||
* See also JCA doc.
|
||||
*/
|
||||
protected Key engineTranslateKey(Key key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key must not be null");
|
||||
}
|
||||
String keyAlg = key.getAlgorithm();
|
||||
if (keyAlg.equals("EC") == false) {
|
||||
throw new InvalidKeyException("Not an EC key: " + keyAlg);
|
||||
}
|
||||
if (key instanceof PublicKey) {
|
||||
return implTranslatePublicKey((PublicKey)key);
|
||||
} else if (key instanceof PrivateKey) {
|
||||
return implTranslatePrivateKey((PrivateKey)key);
|
||||
} else {
|
||||
throw new InvalidKeyException("Neither a public nor a private key");
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
protected PublicKey engineGeneratePublic(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
return implGeneratePublic(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw e;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
return implGeneratePrivate(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw e;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of translateKey() for public keys. See JCA doc
|
||||
private PublicKey implTranslatePublicKey(PublicKey key)
|
||||
throws InvalidKeyException {
|
||||
if (key instanceof ECPublicKey) {
|
||||
if (key instanceof ECPublicKeyImpl) {
|
||||
return key;
|
||||
}
|
||||
ECPublicKey ecKey = (ECPublicKey)key;
|
||||
return new ECPublicKeyImpl(
|
||||
ecKey.getW(),
|
||||
ecKey.getParams()
|
||||
);
|
||||
} else if ("X.509".equals(key.getFormat())) {
|
||||
byte[] encoded = key.getEncoded();
|
||||
return new ECPublicKeyImpl(encoded);
|
||||
} else {
|
||||
throw new InvalidKeyException("Public keys must be instance "
|
||||
+ "of ECPublicKey or have X.509 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of translateKey() for private keys. See JCA doc
|
||||
private PrivateKey implTranslatePrivateKey(PrivateKey key)
|
||||
throws InvalidKeyException {
|
||||
if (key instanceof ECPrivateKey) {
|
||||
if (key instanceof ECPrivateKeyImpl) {
|
||||
return key;
|
||||
}
|
||||
ECPrivateKey ecKey = (ECPrivateKey)key;
|
||||
return new ECPrivateKeyImpl(
|
||||
ecKey.getS(),
|
||||
ecKey.getParams()
|
||||
);
|
||||
} else if ("PKCS#8".equals(key.getFormat())) {
|
||||
return new ECPrivateKeyImpl(key.getEncoded());
|
||||
} else {
|
||||
throw new InvalidKeyException("Private keys must be instance "
|
||||
+ "of ECPrivateKey or have PKCS#8 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of generatePublic. See JCA doc
|
||||
private PublicKey implGeneratePublic(KeySpec keySpec)
|
||||
throws GeneralSecurityException {
|
||||
if (keySpec instanceof X509EncodedKeySpec) {
|
||||
X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
|
||||
return new ECPublicKeyImpl(x509Spec.getEncoded());
|
||||
} else if (keySpec instanceof ECPublicKeySpec) {
|
||||
ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
|
||||
return new ECPublicKeyImpl(
|
||||
ecSpec.getW(),
|
||||
ecSpec.getParams()
|
||||
);
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Only ECPublicKeySpec "
|
||||
+ "and X509EncodedKeySpec supported for EC public keys");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of generatePrivate. See JCA doc
|
||||
private PrivateKey implGeneratePrivate(KeySpec keySpec)
|
||||
throws GeneralSecurityException {
|
||||
if (keySpec instanceof PKCS8EncodedKeySpec) {
|
||||
PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
|
||||
return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
|
||||
} else if (keySpec instanceof ECPrivateKeySpec) {
|
||||
ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
|
||||
return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Only ECPrivateKeySpec "
|
||||
+ "and PKCS8EncodedKeySpec supported for EC private keys");
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
// convert key to one of our keys
|
||||
// this also verifies that the key is a valid EC key and ensures
|
||||
// that the encoding is X.509/PKCS#8 for public/private keys
|
||||
key = engineTranslateKey(key);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
if (key instanceof ECPublicKey) {
|
||||
ECPublicKey ecKey = (ECPublicKey)key;
|
||||
if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) {
|
||||
return keySpec.cast(new ECPublicKeySpec(
|
||||
ecKey.getW(),
|
||||
ecKey.getParams()
|
||||
));
|
||||
} else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) {
|
||||
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("KeySpec must be ECPublicKeySpec or "
|
||||
+ "X509EncodedKeySpec for EC public keys");
|
||||
}
|
||||
} else if (key instanceof ECPrivateKey) {
|
||||
if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) {
|
||||
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
|
||||
} else if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) {
|
||||
ECPrivateKey ecKey = (ECPrivateKey)key;
|
||||
return keySpec.cast(new ECPrivateKeySpec(
|
||||
ecKey.getS(),
|
||||
ecKey.getParams()
|
||||
));
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("KeySpec must be ECPrivateKeySpec or "
|
||||
+ "PKCS8EncodedKeySpec for EC private keys");
|
||||
}
|
||||
} else {
|
||||
// should not occur, caught in engineTranslateKey()
|
||||
throw new InvalidKeySpecException("Neither public nor private key");
|
||||
}
|
||||
}
|
||||
}
|
||||
268
jdkSrc/jdk8/sun/security/ec/ECKeyPairGenerator.java
Normal file
268
jdkSrc/jdk8/sun/security/ec/ECKeyPairGenerator.java
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.util.Optional;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
import sun.security.util.ECUtil;
|
||||
import sun.security.util.math.*;
|
||||
import sun.security.ec.point.*;
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
|
||||
import static sun.security.ec.ECOperations.IntermediateValueException;
|
||||
|
||||
/**
|
||||
* EC keypair generator.
|
||||
* Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
|
||||
private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
|
||||
private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
|
||||
|
||||
// used to seed the keypair generator
|
||||
private SecureRandom random;
|
||||
|
||||
// size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
|
||||
private int keySize;
|
||||
|
||||
// parameters specified via init, if any
|
||||
private AlgorithmParameterSpec params = null;
|
||||
|
||||
/**
|
||||
* Constructs a new ECKeyPairGenerator.
|
||||
*/
|
||||
public ECKeyPairGenerator() {
|
||||
// initialize to default in case the app does not call initialize()
|
||||
initialize(DEF_EC_KEY_SIZE, null);
|
||||
}
|
||||
|
||||
// initialize the generator. See JCA doc
|
||||
@Override
|
||||
public void initialize(int keySize, SecureRandom random) {
|
||||
|
||||
checkKeySize(keySize);
|
||||
this.params = ECUtil.getECParameterSpec(null, keySize);
|
||||
if (params == null) {
|
||||
throw new InvalidParameterException(
|
||||
"No EC parameters available for key size " + keySize + " bits");
|
||||
}
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
// second initialize method. See JCA doc
|
||||
@Override
|
||||
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
||||
ECParameterSpec ecSpec = null;
|
||||
|
||||
if (params instanceof ECParameterSpec) {
|
||||
ECParameterSpec ecParams = (ECParameterSpec) params;
|
||||
ecSpec = ECUtil.getECParameterSpec(null, ecParams);
|
||||
if (ecSpec == null) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Unsupported curve: " + params);
|
||||
}
|
||||
} else if (params instanceof ECGenParameterSpec) {
|
||||
String name = ((ECGenParameterSpec) params).getName();
|
||||
ecSpec = ECUtil.getECParameterSpec(null, name);
|
||||
if (ecSpec == null) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Unknown curve name: " + name);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"ECParameterSpec or ECGenParameterSpec required for EC");
|
||||
}
|
||||
|
||||
// Not all known curves are supported by the native implementation
|
||||
ensureCurveIsSupported(ecSpec);
|
||||
this.params = ecSpec;
|
||||
|
||||
this.keySize = ecSpec.getCurve().getField().getFieldSize();
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
||||
AlgorithmParameters ecParams = ECUtil.getECParameters(null);
|
||||
byte[] encodedParams;
|
||||
try {
|
||||
ecParams.init(ecSpec);
|
||||
encodedParams = ecParams.getEncoded();
|
||||
} catch (InvalidParameterSpecException ex) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Unsupported curve: " + ecSpec.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
if (!isCurveSupported(encodedParams)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Unsupported curve: " + ecParams.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// generate the keypair. See JCA doc
|
||||
@Override
|
||||
public KeyPair generateKeyPair() {
|
||||
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
|
||||
try {
|
||||
Optional<KeyPair> kp = generateKeyPairImpl(random);
|
||||
if (kp.isPresent()) {
|
||||
return kp.get();
|
||||
}
|
||||
return generateKeyPairNative(random);
|
||||
} catch (Exception ex) {
|
||||
throw new ProviderException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] generatePrivateScalar(SecureRandom random,
|
||||
ECOperations ecOps, int seedSize) {
|
||||
// Attempt to create the private scalar in a loop that uses new random
|
||||
// input each time. The chance of failure is very small assuming the
|
||||
// implementation derives the nonce using extra bits
|
||||
int numAttempts = 128;
|
||||
byte[] seedArr = new byte[seedSize];
|
||||
for (int i = 0; i < numAttempts; i++) {
|
||||
random.nextBytes(seedArr);
|
||||
try {
|
||||
return ecOps.seedToScalar(seedArr);
|
||||
} catch (IntermediateValueException ex) {
|
||||
// try again in the next iteration
|
||||
}
|
||||
}
|
||||
|
||||
throw new ProviderException("Unable to produce private key after "
|
||||
+ numAttempts + " attempts");
|
||||
}
|
||||
|
||||
private Optional<KeyPair> generateKeyPairImpl(SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
|
||||
ECParameterSpec ecParams = (ECParameterSpec) params;
|
||||
|
||||
Optional<ECOperations> opsOpt = ECOperations.forParameters(ecParams);
|
||||
if (!opsOpt.isPresent()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ECOperations ops = opsOpt.get();
|
||||
IntegerFieldModuloP field = ops.getField();
|
||||
int numBits = ecParams.getOrder().bitLength();
|
||||
int seedBits = numBits + 64;
|
||||
int seedSize = (seedBits + 7) / 8;
|
||||
byte[] privArr = generatePrivateScalar(random, ops, seedSize);
|
||||
|
||||
ECPoint genPoint = ecParams.getGenerator();
|
||||
ImmutableIntegerModuloP x = field.getElement(genPoint.getAffineX());
|
||||
ImmutableIntegerModuloP y = field.getElement(genPoint.getAffineY());
|
||||
AffinePoint affGen = new AffinePoint(x, y);
|
||||
Point pub = ops.multiply(affGen, privArr);
|
||||
AffinePoint affPub = pub.asAffine();
|
||||
|
||||
PrivateKey privateKey = new ECPrivateKeyImpl(privArr, ecParams);
|
||||
|
||||
ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
|
||||
affPub.getY().asBigInteger());
|
||||
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
|
||||
|
||||
return Optional.of(new KeyPair(publicKey, privateKey));
|
||||
}
|
||||
|
||||
private KeyPair generateKeyPairNative(SecureRandom random)
|
||||
throws Exception {
|
||||
|
||||
ECParameterSpec ecParams = (ECParameterSpec) params;
|
||||
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, ecParams);
|
||||
|
||||
// seed is twice the key size (in bytes) plus 1
|
||||
byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
|
||||
random.nextBytes(seed);
|
||||
Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed);
|
||||
|
||||
// The 'params' object supplied above is equivalent to the native
|
||||
// one so there is no need to fetch it.
|
||||
// keyBytes[0] is the encoding of the native private key
|
||||
BigInteger s = new BigInteger(1, (byte[]) keyBytes[0]);
|
||||
|
||||
PrivateKey privateKey = new ECPrivateKeyImpl(s, ecParams);
|
||||
|
||||
// keyBytes[1] is the encoding of the native public key
|
||||
byte[] pubKey = (byte[]) keyBytes[1];
|
||||
ECPoint w = ECUtil.decodePoint(pubKey, ecParams.getCurve());
|
||||
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
|
||||
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
}
|
||||
|
||||
private void checkKeySize(int keySize) throws InvalidParameterException {
|
||||
if (keySize < KEY_SIZE_MIN) {
|
||||
throw new InvalidParameterException
|
||||
("Key size must be at least " + KEY_SIZE_MIN + " bits");
|
||||
}
|
||||
if (keySize > KEY_SIZE_MAX) {
|
||||
throw new InvalidParameterException
|
||||
("Key size must be at most " + KEY_SIZE_MAX + " bits");
|
||||
}
|
||||
this.keySize = keySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the curve in the encoded parameters is supported by the
|
||||
* native implementation. Some curve operations will be performed by the
|
||||
* Java implementation, but not all of them. So native support is still
|
||||
* required for all curves.
|
||||
*
|
||||
* @param encodedParams encoded parameters in the same form accepted
|
||||
* by generateECKeyPair
|
||||
* @return true if and only if generateECKeyPair will succeed for
|
||||
* the supplied parameters
|
||||
*/
|
||||
private static native boolean isCurveSupported(byte[] encodedParams);
|
||||
|
||||
/*
|
||||
* Generates the keypair and returns a 2-element array of encoding bytes.
|
||||
* The first one is for the private key, the second for the public key.
|
||||
*/
|
||||
private static native Object[] generateECKeyPair(int keySize,
|
||||
byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
|
||||
}
|
||||
499
jdkSrc/jdk8/sun/security/ec/ECOperations.java
Normal file
499
jdkSrc/jdk8/sun/security/ec/ECOperations.java
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import sun.security.ec.point.*;
|
||||
import sun.security.util.math.*;
|
||||
import sun.security.util.math.intpoly.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/*
|
||||
* Elliptic curve point arithmetic for prime-order curves where a=-3.
|
||||
* Formulas are derived from "Complete addition formulas for prime order
|
||||
* elliptic curves" by Renes, Costello, and Batina.
|
||||
*/
|
||||
|
||||
public class ECOperations {
|
||||
|
||||
/*
|
||||
* An exception indicating a problem with an intermediate value produced
|
||||
* by some part of the computation. For example, the signing operation
|
||||
* will throw this exception to indicate that the r or s value is 0, and
|
||||
* that the signing operation should be tried again with a different nonce.
|
||||
*/
|
||||
static class IntermediateValueException extends Exception {
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
static final Map<BigInteger, IntegerFieldModuloP> fields;
|
||||
|
||||
static final Map<BigInteger, IntegerFieldModuloP> orderFields;
|
||||
|
||||
static {
|
||||
Map<BigInteger, IntegerFieldModuloP> map = new HashMap<>();
|
||||
map.put(IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256());
|
||||
map.put(IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384());
|
||||
map.put(IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521());
|
||||
fields = Collections.unmodifiableMap(map);
|
||||
map = new HashMap<>();
|
||||
map.put(P256OrderField.MODULUS, new P256OrderField());
|
||||
map.put(P384OrderField.MODULUS, new P384OrderField());
|
||||
map.put(P521OrderField.MODULUS, new P521OrderField());
|
||||
orderFields = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public static Optional<ECOperations> forParameters(ECParameterSpec params) {
|
||||
|
||||
EllipticCurve curve = params.getCurve();
|
||||
if (!(curve.getField() instanceof ECFieldFp)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ECFieldFp primeField = (ECFieldFp) curve.getField();
|
||||
|
||||
BigInteger three = BigInteger.valueOf(3);
|
||||
if (!primeField.getP().subtract(curve.getA()).equals(three)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
IntegerFieldModuloP field = fields.get(primeField.getP());
|
||||
if (field == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
IntegerFieldModuloP orderField = orderFields.get(params.getOrder());
|
||||
if (orderField == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableIntegerModuloP b = field.getElement(curve.getB());
|
||||
ECOperations ecOps = new ECOperations(b, orderField);
|
||||
return Optional.of(ecOps);
|
||||
}
|
||||
|
||||
final ImmutableIntegerModuloP b;
|
||||
final SmallValue one;
|
||||
final SmallValue two;
|
||||
final SmallValue three;
|
||||
final SmallValue four;
|
||||
final ProjectivePoint.Immutable neutral;
|
||||
private final IntegerFieldModuloP orderField;
|
||||
|
||||
public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {
|
||||
this.b = b.fixed();
|
||||
this.orderField = orderField;
|
||||
|
||||
this.one = b.getField().getSmallValue(1);
|
||||
this.two = b.getField().getSmallValue(2);
|
||||
this.three = b.getField().getSmallValue(3);
|
||||
this.four = b.getField().getSmallValue(4);
|
||||
|
||||
IntegerFieldModuloP field = b.getField();
|
||||
this.neutral = new ProjectivePoint.Immutable(field.get0(),
|
||||
field.get1(), field.get0());
|
||||
}
|
||||
|
||||
public IntegerFieldModuloP getField() {
|
||||
return b.getField();
|
||||
}
|
||||
public IntegerFieldModuloP getOrderField() {
|
||||
return orderField;
|
||||
}
|
||||
|
||||
protected ProjectivePoint.Immutable getNeutral() {
|
||||
return neutral;
|
||||
}
|
||||
|
||||
public boolean isNeutral(Point p) {
|
||||
ProjectivePoint<?> pp = (ProjectivePoint<?>) p;
|
||||
|
||||
IntegerModuloP z = pp.getZ();
|
||||
|
||||
IntegerFieldModuloP field = z.getField();
|
||||
int byteLength = (field.getSize().bitLength() + 7) / 8;
|
||||
byte[] zBytes = z.asByteArray(byteLength);
|
||||
return allZero(zBytes);
|
||||
}
|
||||
|
||||
byte[] seedToScalar(byte[] seedBytes)
|
||||
throws IntermediateValueException {
|
||||
|
||||
// Produce a nonce from the seed using FIPS 186-4,section B.5.1:
|
||||
// Per-Message Secret Number Generation Using Extra Random Bits
|
||||
// or
|
||||
// Produce a scalar from the seed using FIPS 186-4, section B.4.1:
|
||||
// Key Pair Generation Using Extra Random Bits
|
||||
|
||||
// To keep the implementation simple, sample in the range [0,n)
|
||||
// and throw IntermediateValueException in the (unlikely) event
|
||||
// that the result is 0.
|
||||
|
||||
// Get 64 extra bits and reduce in to the nonce
|
||||
int seedBits = orderField.getSize().bitLength() + 64;
|
||||
if (seedBytes.length * 8 < seedBits) {
|
||||
throw new ProviderException("Incorrect seed length: " +
|
||||
seedBytes.length * 8 + " < " + seedBits);
|
||||
}
|
||||
|
||||
// input conversion only works on byte boundaries
|
||||
// clear high-order bits of last byte so they don't influence nonce
|
||||
int lastByteBits = seedBits % 8;
|
||||
if (lastByteBits != 0) {
|
||||
int lastByteIndex = seedBits / 8;
|
||||
byte mask = (byte) (0xFF >>> (8 - lastByteBits));
|
||||
seedBytes[lastByteIndex] &= mask;
|
||||
}
|
||||
|
||||
int seedLength = (seedBits + 7) / 8;
|
||||
IntegerModuloP scalarElem =
|
||||
orderField.getElement(seedBytes, 0, seedLength, (byte) 0);
|
||||
int scalarLength = (orderField.getSize().bitLength() + 7) / 8;
|
||||
byte[] scalarArr = new byte[scalarLength];
|
||||
scalarElem.asByteArray(scalarArr);
|
||||
if (ECOperations.allZero(scalarArr)) {
|
||||
throw new IntermediateValueException();
|
||||
}
|
||||
return scalarArr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare all values in the array to 0 without branching on any value
|
||||
*
|
||||
*/
|
||||
public static boolean allZero(byte[] arr) {
|
||||
byte acc = 0;
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
acc |= arr[i];
|
||||
}
|
||||
return acc == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4-bit branchless array lookup for projective points.
|
||||
*/
|
||||
private void lookup4(ProjectivePoint.Immutable[] arr, int index,
|
||||
ProjectivePoint.Mutable result, IntegerModuloP zero) {
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int xor = index ^ i;
|
||||
int bit3 = (xor & 0x8) >>> 3;
|
||||
int bit2 = (xor & 0x4) >>> 2;
|
||||
int bit1 = (xor & 0x2) >>> 1;
|
||||
int bit0 = (xor & 0x1);
|
||||
int inverse = bit0 | bit1 | bit2 | bit3;
|
||||
int set = 1 - inverse;
|
||||
|
||||
ProjectivePoint.Immutable pi = arr[i];
|
||||
result.conditionalSet(pi, set);
|
||||
}
|
||||
}
|
||||
|
||||
private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
|
||||
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
|
||||
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
setDouble(p, t0, t1, t2, t3, t4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply an affine point by a scalar and return the result as a mutable
|
||||
* point.
|
||||
*
|
||||
* @param affineP the point
|
||||
* @param s the scalar as a little-endian array
|
||||
* @return the product
|
||||
*/
|
||||
public MutablePoint multiply(AffinePoint affineP, byte[] s) {
|
||||
|
||||
// 4-bit windowed multiply with branchless lookup.
|
||||
// The mixed addition is faster, so it is used to construct the array
|
||||
// at the beginning of the operation.
|
||||
|
||||
IntegerFieldModuloP field = affineP.getX().getField();
|
||||
ImmutableIntegerModuloP zero = field.get0();
|
||||
// temporaries
|
||||
MutableIntegerModuloP t0 = zero.mutable();
|
||||
MutableIntegerModuloP t1 = zero.mutable();
|
||||
MutableIntegerModuloP t2 = zero.mutable();
|
||||
MutableIntegerModuloP t3 = zero.mutable();
|
||||
MutableIntegerModuloP t4 = zero.mutable();
|
||||
|
||||
ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);
|
||||
result.getY().setValue(field.get1().mutable());
|
||||
|
||||
ProjectivePoint.Immutable[] pointMultiples =
|
||||
new ProjectivePoint.Immutable[16];
|
||||
// 0P is neutral---same as initial result value
|
||||
pointMultiples[0] = result.fixed();
|
||||
|
||||
ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);
|
||||
ps.setValue(affineP);
|
||||
// 1P = P
|
||||
pointMultiples[1] = ps.fixed();
|
||||
|
||||
// the rest are calculated using mixed point addition
|
||||
for (int i = 2; i < 16; i++) {
|
||||
setSum(ps, affineP, t0, t1, t2, t3, t4);
|
||||
pointMultiples[i] = ps.fixed();
|
||||
}
|
||||
|
||||
ProjectivePoint.Mutable lookupResult = ps.mutable();
|
||||
|
||||
for (int i = s.length - 1; i >= 0; i--) {
|
||||
|
||||
double4(result, t0, t1, t2, t3, t4);
|
||||
|
||||
int high = (0xFF & s[i]) >>> 4;
|
||||
lookup4(pointMultiples, high, lookupResult, zero);
|
||||
setSum(result, lookupResult, t0, t1, t2, t3, t4);
|
||||
|
||||
double4(result, t0, t1, t2, t3, t4);
|
||||
|
||||
int low = 0xF & s[i];
|
||||
lookup4(pointMultiples, low, lookupResult, zero);
|
||||
setSum(result, lookupResult, t0, t1, t2, t3, t4);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Point double
|
||||
*/
|
||||
private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
|
||||
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
|
||||
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
|
||||
|
||||
t0.setValue(p.getX()).setSquare();
|
||||
t1.setValue(p.getY()).setSquare();
|
||||
t2.setValue(p.getZ()).setSquare();
|
||||
t3.setValue(p.getX()).setProduct(p.getY());
|
||||
t4.setValue(p.getY()).setProduct(p.getZ());
|
||||
|
||||
t3.setSum(t3);
|
||||
p.getZ().setProduct(p.getX());
|
||||
|
||||
p.getZ().setProduct(two);
|
||||
|
||||
p.getY().setValue(t2).setProduct(b);
|
||||
p.getY().setDifference(p.getZ());
|
||||
|
||||
p.getX().setValue(p.getY()).setProduct(two);
|
||||
p.getY().setSum(p.getX());
|
||||
p.getY().setReduced();
|
||||
p.getX().setValue(t1).setDifference(p.getY());
|
||||
|
||||
p.getY().setSum(t1);
|
||||
p.getY().setProduct(p.getX());
|
||||
p.getX().setProduct(t3);
|
||||
|
||||
t3.setValue(t2).setProduct(two);
|
||||
t2.setSum(t3);
|
||||
p.getZ().setProduct(b);
|
||||
|
||||
t2.setReduced();
|
||||
p.getZ().setDifference(t2);
|
||||
p.getZ().setDifference(t0);
|
||||
t3.setValue(p.getZ()).setProduct(two);
|
||||
p.getZ().setReduced();
|
||||
p.getZ().setSum(t3);
|
||||
t0.setProduct(three);
|
||||
|
||||
t0.setDifference(t2);
|
||||
t0.setProduct(p.getZ());
|
||||
p.getY().setSum(t0);
|
||||
|
||||
t4.setSum(t4);
|
||||
p.getZ().setProduct(t4);
|
||||
|
||||
p.getX().setDifference(p.getZ());
|
||||
p.getZ().setValue(t4).setProduct(t1);
|
||||
|
||||
p.getZ().setProduct(four);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixed point addition. This method constructs new temporaries each time
|
||||
* it is called. For better efficiency, the method that reuses temporaries
|
||||
* should be used if more than one sum will be computed.
|
||||
*/
|
||||
public void setSum(MutablePoint p, AffinePoint p2) {
|
||||
|
||||
IntegerModuloP zero = p.getField().get0();
|
||||
MutableIntegerModuloP t0 = zero.mutable();
|
||||
MutableIntegerModuloP t1 = zero.mutable();
|
||||
MutableIntegerModuloP t2 = zero.mutable();
|
||||
MutableIntegerModuloP t3 = zero.mutable();
|
||||
MutableIntegerModuloP t4 = zero.mutable();
|
||||
setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixed point addition
|
||||
*/
|
||||
private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
|
||||
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
|
||||
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
|
||||
MutableIntegerModuloP t4) {
|
||||
|
||||
t0.setValue(p.getX()).setProduct(p2.getX());
|
||||
t1.setValue(p.getY()).setProduct(p2.getY());
|
||||
t3.setValue(p2.getX()).setSum(p2.getY());
|
||||
t4.setValue(p.getX()).setSum(p.getY());
|
||||
p.getX().setReduced();
|
||||
t3.setProduct(t4);
|
||||
t4.setValue(t0).setSum(t1);
|
||||
|
||||
t3.setDifference(t4);
|
||||
t4.setValue(p2.getY()).setProduct(p.getZ());
|
||||
t4.setSum(p.getY());
|
||||
|
||||
p.getY().setValue(p2.getX()).setProduct(p.getZ());
|
||||
p.getY().setSum(p.getX());
|
||||
t2.setValue(p.getZ());
|
||||
p.getZ().setProduct(b);
|
||||
|
||||
p.getX().setValue(p.getY()).setDifference(p.getZ());
|
||||
p.getX().setReduced();
|
||||
p.getZ().setValue(p.getX()).setProduct(two);
|
||||
p.getX().setSum(p.getZ());
|
||||
|
||||
p.getZ().setValue(t1).setDifference(p.getX());
|
||||
p.getX().setSum(t1);
|
||||
p.getY().setProduct(b);
|
||||
|
||||
t1.setValue(t2).setProduct(two);
|
||||
t2.setSum(t1);
|
||||
t2.setReduced();
|
||||
p.getY().setDifference(t2);
|
||||
|
||||
p.getY().setDifference(t0);
|
||||
p.getY().setReduced();
|
||||
t1.setValue(p.getY()).setProduct(two);
|
||||
p.getY().setSum(t1);
|
||||
|
||||
t1.setValue(t0).setProduct(two);
|
||||
t0.setSum(t1);
|
||||
t0.setDifference(t2);
|
||||
|
||||
t1.setValue(t4).setProduct(p.getY());
|
||||
t2.setValue(t0).setProduct(p.getY());
|
||||
p.getY().setValue(p.getX()).setProduct(p.getZ());
|
||||
|
||||
p.getY().setSum(t2);
|
||||
p.getX().setProduct(t3);
|
||||
p.getX().setDifference(t1);
|
||||
|
||||
p.getZ().setProduct(t4);
|
||||
t1.setValue(t3).setProduct(t0);
|
||||
p.getZ().setSum(t1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Projective point addition
|
||||
*/
|
||||
private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,
|
||||
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
|
||||
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
|
||||
MutableIntegerModuloP t4) {
|
||||
|
||||
t0.setValue(p.getX()).setProduct(p2.getX());
|
||||
t1.setValue(p.getY()).setProduct(p2.getY());
|
||||
t2.setValue(p.getZ()).setProduct(p2.getZ());
|
||||
|
||||
t3.setValue(p.getX()).setSum(p.getY());
|
||||
t4.setValue(p2.getX()).setSum(p2.getY());
|
||||
t3.setProduct(t4);
|
||||
|
||||
t4.setValue(t0).setSum(t1);
|
||||
t3.setDifference(t4);
|
||||
t4.setValue(p.getY()).setSum(p.getZ());
|
||||
|
||||
p.getY().setValue(p2.getY()).setSum(p2.getZ());
|
||||
t4.setProduct(p.getY());
|
||||
p.getY().setValue(t1).setSum(t2);
|
||||
|
||||
t4.setDifference(p.getY());
|
||||
p.getX().setSum(p.getZ());
|
||||
p.getY().setValue(p2.getX()).setSum(p2.getZ());
|
||||
|
||||
p.getX().setProduct(p.getY());
|
||||
p.getY().setValue(t0).setSum(t2);
|
||||
p.getY().setAdditiveInverse().setSum(p.getX());
|
||||
p.getY().setReduced();
|
||||
|
||||
p.getZ().setValue(t2).setProduct(b);
|
||||
p.getX().setValue(p.getY()).setDifference(p.getZ());
|
||||
p.getZ().setValue(p.getX()).setProduct(two);
|
||||
|
||||
p.getX().setSum(p.getZ());
|
||||
p.getX().setReduced();
|
||||
p.getZ().setValue(t1).setDifference(p.getX());
|
||||
p.getX().setSum(t1);
|
||||
|
||||
p.getY().setProduct(b);
|
||||
t1.setValue(t2).setSum(t2);
|
||||
t2.setSum(t1);
|
||||
t2.setReduced();
|
||||
|
||||
p.getY().setDifference(t2);
|
||||
p.getY().setDifference(t0);
|
||||
p.getY().setReduced();
|
||||
t1.setValue(p.getY()).setSum(p.getY());
|
||||
|
||||
p.getY().setSum(t1);
|
||||
t1.setValue(t0).setProduct(two);
|
||||
t0.setSum(t1);
|
||||
|
||||
t0.setDifference(t2);
|
||||
t1.setValue(t4).setProduct(p.getY());
|
||||
t2.setValue(t0).setProduct(p.getY());
|
||||
|
||||
p.getY().setValue(p.getX()).setProduct(p.getZ());
|
||||
p.getY().setSum(t2);
|
||||
p.getX().setProduct(t3);
|
||||
|
||||
p.getX().setDifference(t1);
|
||||
p.getZ().setProduct(t4);
|
||||
t1.setValue(t3).setProduct(t0);
|
||||
|
||||
p.getZ().setSum(t1);
|
||||
|
||||
}
|
||||
}
|
||||
233
jdkSrc/jdk8/sun/security/ec/ECPrivateKeyImpl.java
Normal file
233
jdkSrc/jdk8/sun/security/ec/ECPrivateKeyImpl.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import sun.security.util.ArrayUtil;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.ECParameters;
|
||||
import sun.security.util.ECUtil;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
|
||||
/**
|
||||
* Key implementation for EC private keys.
|
||||
* <p>
|
||||
* ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):
|
||||
*
|
||||
* <pre>
|
||||
* EXPLICIT TAGS
|
||||
*
|
||||
* ECPrivateKey ::= SEQUENCE {
|
||||
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
|
||||
* privateKey OCTET STRING,
|
||||
* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
|
||||
* publicKey [1] BIT STRING OPTIONAL
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* We currently ignore the optional parameters and publicKey fields. We
|
||||
* require that the parameters are encoded as part of the AlgorithmIdentifier,
|
||||
* not in the private key structure.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
|
||||
|
||||
private static final long serialVersionUID = 88695385615075129L;
|
||||
|
||||
private BigInteger s; // private value
|
||||
private byte[] arrayS; // private value as a little-endian array
|
||||
private ECParameterSpec params;
|
||||
|
||||
/**
|
||||
* Construct a key from its encoding. Called by the ECKeyFactory.
|
||||
*/
|
||||
public ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||
decode(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a key from its components. Used by the
|
||||
* KeyFactory.
|
||||
*/
|
||||
public ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
|
||||
throws InvalidKeyException {
|
||||
this.s = s;
|
||||
this.params = params;
|
||||
makeEncoding(s);
|
||||
|
||||
}
|
||||
|
||||
ECPrivateKeyImpl(byte[] s, ECParameterSpec params)
|
||||
throws InvalidKeyException {
|
||||
this.arrayS = s.clone();
|
||||
this.params = params;
|
||||
makeEncoding(s);
|
||||
}
|
||||
|
||||
private void makeEncoding(byte[] s) throws InvalidKeyException {
|
||||
algid = new AlgorithmId
|
||||
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
|
||||
try {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(1); // version 1
|
||||
byte[] privBytes = s.clone();
|
||||
ArrayUtil.reverse(privBytes);
|
||||
out.putOctetString(privBytes);
|
||||
DerValue val =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
key = val.toByteArray();
|
||||
} catch (IOException exc) {
|
||||
// should never occur
|
||||
throw new InvalidKeyException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeEncoding(BigInteger s) throws InvalidKeyException {
|
||||
algid = new AlgorithmId
|
||||
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
|
||||
try {
|
||||
byte[] sArr = s.toByteArray();
|
||||
// convert to fixed-length array
|
||||
int numOctets = (params.getOrder().bitLength() + 7) / 8;
|
||||
byte[] sOctets = new byte[numOctets];
|
||||
int inPos = Math.max(sArr.length - sOctets.length, 0);
|
||||
int outPos = Math.max(sOctets.length - sArr.length, 0);
|
||||
int length = Math.min(sArr.length, sOctets.length);
|
||||
System.arraycopy(sArr, inPos, sOctets, outPos, length);
|
||||
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(1); // version 1
|
||||
out.putOctetString(sOctets);
|
||||
DerValue val =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
key = val.toByteArray();
|
||||
} catch (IOException exc) {
|
||||
// should never occur
|
||||
throw new InvalidKeyException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public String getAlgorithm() {
|
||||
return "EC";
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public BigInteger getS() {
|
||||
if (s == null) {
|
||||
byte[] arrCopy = arrayS.clone();
|
||||
ArrayUtil.reverse(arrCopy);
|
||||
s = new BigInteger(1, arrCopy);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public byte[] getArrayS() {
|
||||
if (arrayS == null) {
|
||||
byte[] arr = getS().toByteArray();
|
||||
ArrayUtil.reverse(arr);
|
||||
int byteLength = (params.getOrder().bitLength() + 7) / 8;
|
||||
arrayS = new byte[byteLength];
|
||||
int length = Math.min(byteLength, arr.length);
|
||||
System.arraycopy(arr, 0, arrayS, 0, length);
|
||||
}
|
||||
return arrayS.clone();
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public ECParameterSpec getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the key. Called by PKCS8Key.
|
||||
*/
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
try {
|
||||
DerInputStream in = new DerInputStream(key);
|
||||
DerValue derValue = in.getDerValue();
|
||||
if (derValue.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Not a SEQUENCE");
|
||||
}
|
||||
DerInputStream data = derValue.data;
|
||||
int version = data.getInteger();
|
||||
if (version != 1) {
|
||||
throw new IOException("Version must be 1");
|
||||
}
|
||||
byte[] privData = data.getOctetString();
|
||||
ArrayUtil.reverse(privData);
|
||||
arrayS = privData;
|
||||
while (data.available() != 0) {
|
||||
DerValue value = data.getDerValue();
|
||||
if (value.isContextSpecific((byte) 0)) {
|
||||
// ignore for now
|
||||
} else if (value.isContextSpecific((byte) 1)) {
|
||||
// ignore for now
|
||||
} else {
|
||||
throw new InvalidKeyException("Unexpected value: " + value);
|
||||
}
|
||||
}
|
||||
AlgorithmParameters algParams = this.algid.getParameters();
|
||||
if (algParams == null) {
|
||||
throw new InvalidKeyException("EC domain parameters must be "
|
||||
+ "encoded in the algorithm identifier");
|
||||
}
|
||||
params = algParams.getParameterSpec(ECParameterSpec.class);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid EC private key", e);
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
throw new InvalidKeyException("Invalid EC private key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"ECPrivateKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
148
jdkSrc/jdk8/sun/security/ec/ECPublicKeyImpl.java
Normal file
148
jdkSrc/jdk8/sun/security/ec/ECPublicKeyImpl.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import sun.security.util.ECParameters;
|
||||
import sun.security.util.ECUtil;
|
||||
|
||||
import sun.security.x509.*;
|
||||
|
||||
/**
|
||||
* Key implementation for EC public keys.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class ECPublicKeyImpl extends X509Key implements ECPublicKey {
|
||||
|
||||
private static final long serialVersionUID = -2462037275160462289L;
|
||||
|
||||
private ECPoint w;
|
||||
private ECParameterSpec params;
|
||||
|
||||
/**
|
||||
* Construct a key from its components. Used by the
|
||||
* ECKeyFactory.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public ECPublicKeyImpl(ECPoint w, ECParameterSpec params)
|
||||
throws InvalidKeyException {
|
||||
this.w = w;
|
||||
this.params = params;
|
||||
// generate the encoding
|
||||
algid = new AlgorithmId
|
||||
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
|
||||
key = ECUtil.encodePoint(w, params.getCurve());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a key from its encoding.
|
||||
*/
|
||||
public ECPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||
decode(encoded);
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public String getAlgorithm() {
|
||||
return "EC";
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public ECPoint getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
public ECParameterSpec getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
// Internal API to get the encoded point. Currently used by SunPKCS11.
|
||||
// This may change/go away depending on what we do with the public API.
|
||||
@SuppressWarnings("deprecation")
|
||||
public byte[] getEncodedPublicValue() {
|
||||
return key.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the key. Called by X509Key.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
AlgorithmParameters algParams = this.algid.getParameters();
|
||||
if (algParams == null) {
|
||||
throw new InvalidKeyException("EC domain parameters must be " +
|
||||
"encoded in the algorithm identifier");
|
||||
}
|
||||
|
||||
try {
|
||||
params = algParams.getParameterSpec(ECParameterSpec.class);
|
||||
w = ECUtil.decodePoint(key, params.getCurve());
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid EC key", e);
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
throw new InvalidKeyException("Invalid EC key", e);
|
||||
}
|
||||
}
|
||||
|
||||
// return a string representation of this key for debugging
|
||||
public String toString() {
|
||||
return "Sun EC public key, " + params.getCurve().getField().getFieldSize()
|
||||
+ " bits\n public x coord: " + w.getAffineX()
|
||||
+ "\n public y coord: " + w.getAffineY()
|
||||
+ "\n parameters: " + params;
|
||||
}
|
||||
|
||||
private Object writeReplace() throws java.io.ObjectStreamException {
|
||||
return new KeyRep(KeyRep.Type.PUBLIC,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"ECPublicKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
84
jdkSrc/jdk8/sun/security/ec/SunEC.java
Normal file
84
jdkSrc/jdk8/sun/security/ec/SunEC.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
/**
|
||||
* Provider class for the Elliptic Curve provider.
|
||||
* Supports EC keypair and parameter generation, ECDSA signing and
|
||||
* ECDH key agreement.
|
||||
*
|
||||
* IMPLEMENTATION NOTE:
|
||||
* The Java classes in this provider access a native ECC implementation
|
||||
* via JNI to a C++ wrapper class which in turn calls C functions.
|
||||
* The Java classes are packaged into the signed sunec.jar in the JRE
|
||||
* extensions directory and the C++ and C functions are packaged into
|
||||
* libsunec.so or sunec.dll in the JRE native libraries directory.
|
||||
* If the native library is not present then this provider is registered
|
||||
* with support for fewer ECC algorithms (KeyPairGenerator, Signature and
|
||||
* KeyAgreement are omitted).
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public final class SunEC extends Provider {
|
||||
|
||||
private static final long serialVersionUID = -2279741672933606418L;
|
||||
|
||||
// flag indicating whether the full EC implementation is present
|
||||
// (when native library is absent then fewer EC algorithms are available)
|
||||
private static boolean useFullImplementation = true;
|
||||
static {
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("sunec"); // check for native library
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
useFullImplementation = false;
|
||||
}
|
||||
}
|
||||
|
||||
public SunEC() {
|
||||
super("SunEC", 1.8d, "Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
|
||||
|
||||
// if there is no security manager installed, put directly into
|
||||
// the provider. Otherwise, create a temporary map and use a
|
||||
// doPrivileged() call at the end to transfer the contents
|
||||
if (System.getSecurityManager() == null) {
|
||||
SunECEntries.putEntries(this, useFullImplementation);
|
||||
} else {
|
||||
Map<Object, Object> map = new HashMap<Object, Object>();
|
||||
SunECEntries.putEntries(map, useFullImplementation);
|
||||
AccessController.doPrivileged(new PutAllAction(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
171
jdkSrc/jdk8/sun/security/ec/SunECEntries.java
Normal file
171
jdkSrc/jdk8/sun/security/ec/SunECEntries.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import sun.security.util.CurveDB;
|
||||
import sun.security.util.NamedCurve;
|
||||
|
||||
/**
|
||||
* Defines the entries of the SunEC provider.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
final class SunECEntries {
|
||||
|
||||
private SunECEntries() {
|
||||
// empty
|
||||
}
|
||||
|
||||
static void putEntries(Map<Object, Object> map,
|
||||
boolean useFullImplementation) {
|
||||
|
||||
/*
|
||||
* Key Factory engine
|
||||
*/
|
||||
map.put("KeyFactory.EC", "sun.security.ec.ECKeyFactory");
|
||||
map.put("Alg.Alias.KeyFactory.EllipticCurve", "EC");
|
||||
|
||||
map.put("KeyFactory.EC ImplementedIn", "Software");
|
||||
|
||||
/*
|
||||
* Algorithm Parameter engine
|
||||
*/
|
||||
map.put("AlgorithmParameters.EC", "sun.security.util.ECParameters");
|
||||
map.put("Alg.Alias.AlgorithmParameters.EllipticCurve", "EC");
|
||||
map.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC");
|
||||
|
||||
map.put("AlgorithmParameters.EC KeySize", "256");
|
||||
|
||||
map.put("AlgorithmParameters.EC ImplementedIn", "Software");
|
||||
|
||||
// "AlgorithmParameters.EC SupportedCurves" prop used by unit test
|
||||
boolean firstCurve = true;
|
||||
StringBuilder names = new StringBuilder();
|
||||
Pattern nameSplitPattern = Pattern.compile(CurveDB.SPLIT_PATTERN);
|
||||
|
||||
Collection<? extends NamedCurve> supportedCurves =
|
||||
CurveDB.getSupportedCurves();
|
||||
for (NamedCurve namedCurve : supportedCurves) {
|
||||
if (!firstCurve) {
|
||||
names.append("|");
|
||||
} else {
|
||||
firstCurve = false;
|
||||
}
|
||||
|
||||
names.append("[");
|
||||
|
||||
String[] commonNames = nameSplitPattern.split(namedCurve.getName());
|
||||
for (String commonName : commonNames) {
|
||||
names.append(commonName.trim());
|
||||
names.append(",");
|
||||
}
|
||||
|
||||
names.append(namedCurve.getObjectId());
|
||||
names.append("]");
|
||||
}
|
||||
|
||||
map.put("AlgorithmParameters.EC SupportedCurves", names.toString());
|
||||
|
||||
/*
|
||||
* Register the algorithms below only when the full ECC implementation
|
||||
* is available
|
||||
*/
|
||||
if (!useFullImplementation) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signature engines
|
||||
*/
|
||||
map.put("Signature.NONEwithECDSA",
|
||||
"sun.security.ec.ECDSASignature$Raw");
|
||||
map.put("Signature.SHA1withECDSA",
|
||||
"sun.security.ec.ECDSASignature$SHA1");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.1", "SHA1withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
|
||||
|
||||
map.put("Signature.SHA224withECDSA",
|
||||
"sun.security.ec.ECDSASignature$SHA224");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.1", "SHA224withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
|
||||
|
||||
map.put("Signature.SHA256withECDSA",
|
||||
"sun.security.ec.ECDSASignature$SHA256");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.2", "SHA256withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
|
||||
|
||||
map.put("Signature.SHA384withECDSA",
|
||||
"sun.security.ec.ECDSASignature$SHA384");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.3", "SHA384withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
|
||||
|
||||
map.put("Signature.SHA512withECDSA",
|
||||
"sun.security.ec.ECDSASignature$SHA512");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.4", "SHA512withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
|
||||
|
||||
String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
|
||||
"|java.security.interfaces.ECPrivateKey";
|
||||
map.put("Signature.NONEwithECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
map.put("Signature.SHA1withECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
map.put("Signature.SHA224withECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
map.put("Signature.SHA256withECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
map.put("Signature.SHA384withECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
map.put("Signature.SHA512withECDSA SupportedKeyClasses", ecKeyClasses);
|
||||
|
||||
map.put("Signature.SHA1withECDSA KeySize", "256");
|
||||
|
||||
map.put("Signature.NONEwithECDSA ImplementedIn", "Software");
|
||||
map.put("Signature.SHA1withECDSA ImplementedIn", "Software");
|
||||
map.put("Signature.SHA224withECDSA ImplementedIn", "Software");
|
||||
map.put("Signature.SHA256withECDSA ImplementedIn", "Software");
|
||||
map.put("Signature.SHA384withECDSA ImplementedIn", "Software");
|
||||
map.put("Signature.SHA512withECDSA ImplementedIn", "Software");
|
||||
|
||||
/*
|
||||
* Key Pair Generator engine
|
||||
*/
|
||||
map.put("KeyPairGenerator.EC", "sun.security.ec.ECKeyPairGenerator");
|
||||
map.put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC");
|
||||
|
||||
map.put("KeyPairGenerator.EC KeySize", "256");
|
||||
|
||||
map.put("KeyPairGenerator.EC ImplementedIn", "Software");
|
||||
|
||||
/*
|
||||
* Key Agreement engine
|
||||
*/
|
||||
map.put("KeyAgreement.ECDH", "sun.security.ec.ECDHKeyAgreement");
|
||||
|
||||
map.put("KeyAgreement.ECDH SupportedKeyClasses", ecKeyClasses);
|
||||
|
||||
map.put("KeyAgreement.ECDH ImplementedIn", "Software");
|
||||
}
|
||||
}
|
||||
76
jdkSrc/jdk8/sun/security/ec/point/AffinePoint.java
Normal file
76
jdkSrc/jdk8/sun/security/ec/point/AffinePoint.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.ec.point;
|
||||
|
||||
import sun.security.util.math.ImmutableIntegerModuloP;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Elliptic curve point represented using affine coordinates (x, y). This class
|
||||
* is not part of the sun.security.ec.point.Point hierarchy because it is not
|
||||
* used to hold intermediate values during point arithmetic, and so it does not
|
||||
* have a mutable form.
|
||||
*/
|
||||
public class AffinePoint {
|
||||
|
||||
private final ImmutableIntegerModuloP x;
|
||||
private final ImmutableIntegerModuloP y;
|
||||
|
||||
public AffinePoint(ImmutableIntegerModuloP x, ImmutableIntegerModuloP y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public ImmutableIntegerModuloP getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public ImmutableIntegerModuloP getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof AffinePoint)) {
|
||||
return false;
|
||||
}
|
||||
AffinePoint p = (AffinePoint) obj;
|
||||
boolean xEquals = x.asBigInteger().equals(p.x.asBigInteger());
|
||||
boolean yEquals = y.asBigInteger().equals(p.y.asBigInteger());
|
||||
return xEquals && yEquals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x.asBigInteger().toString() + "," +
|
||||
y.asBigInteger().toString() + ")";
|
||||
}
|
||||
}
|
||||
32
jdkSrc/jdk8/sun/security/ec/point/ImmutablePoint.java
Normal file
32
jdkSrc/jdk8/sun/security/ec/point/ImmutablePoint.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec.point;
|
||||
|
||||
/**
|
||||
* An interface for immutable points on an elliptic curve over a finite field.
|
||||
*/
|
||||
public interface ImmutablePoint extends Point {
|
||||
}
|
||||
37
jdkSrc/jdk8/sun/security/ec/point/MutablePoint.java
Normal file
37
jdkSrc/jdk8/sun/security/ec/point/MutablePoint.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec.point;
|
||||
|
||||
/**
|
||||
* An interface for mutable points on an elliptic curve over a finite field.
|
||||
*/
|
||||
public interface MutablePoint extends Point {
|
||||
|
||||
MutablePoint setValue(AffinePoint p);
|
||||
MutablePoint setValue(Point p);
|
||||
MutablePoint conditionalSet(Point p, int set);
|
||||
|
||||
}
|
||||
45
jdkSrc/jdk8/sun/security/ec/point/Point.java
Normal file
45
jdkSrc/jdk8/sun/security/ec/point/Point.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.ec.point;
|
||||
|
||||
import sun.security.util.math.IntegerFieldModuloP;
|
||||
|
||||
/**
|
||||
* A base interface for points on an elliptic curve over a finite field.
|
||||
* Implementations may use different representations for points, and this
|
||||
* interface creates a common API for manipulating points. This API has no
|
||||
* methods for point arithmetic, which depends on group structure and curve
|
||||
* parameters in addition to point representation.
|
||||
*/
|
||||
public interface Point {
|
||||
|
||||
IntegerFieldModuloP getField();
|
||||
AffinePoint asAffine();
|
||||
|
||||
ImmutablePoint fixed();
|
||||
MutablePoint mutable();
|
||||
|
||||
}
|
||||
160
jdkSrc/jdk8/sun/security/ec/point/ProjectivePoint.java
Normal file
160
jdkSrc/jdk8/sun/security/ec/point/ProjectivePoint.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.ec.point;
|
||||
|
||||
import sun.security.util.math.*;
|
||||
|
||||
/**
|
||||
* Elliptic curve point in projective coordinates (X, Y, Z) where
|
||||
* an affine point (x, y) is represented using any (X, Y, Z) s.t.
|
||||
* x = X/Z and y = Y/Z.
|
||||
*/
|
||||
public abstract class ProjectivePoint
|
||||
<T extends IntegerModuloP> implements Point {
|
||||
|
||||
protected final T x;
|
||||
protected final T y;
|
||||
protected final T z;
|
||||
|
||||
protected ProjectivePoint(T x, T y, T z) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegerFieldModuloP getField() {
|
||||
return this.x.getField();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Immutable fixed() {
|
||||
return new Immutable(x.fixed(), y.fixed(), z.fixed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable mutable() {
|
||||
return new Mutable(x.mutable(), y.mutable(), z.mutable());
|
||||
}
|
||||
|
||||
public T getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public T getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public T getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public AffinePoint asAffine() {
|
||||
IntegerModuloP zInv = z.multiplicativeInverse();
|
||||
return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
|
||||
}
|
||||
|
||||
public static class Immutable
|
||||
extends ProjectivePoint<ImmutableIntegerModuloP>
|
||||
implements ImmutablePoint {
|
||||
|
||||
public Immutable(ImmutableIntegerModuloP x,
|
||||
ImmutableIntegerModuloP y,
|
||||
ImmutableIntegerModuloP z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Mutable
|
||||
extends ProjectivePoint<MutableIntegerModuloP>
|
||||
implements MutablePoint {
|
||||
|
||||
public Mutable(MutableIntegerModuloP x,
|
||||
MutableIntegerModuloP y,
|
||||
MutableIntegerModuloP z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
|
||||
public Mutable(IntegerFieldModuloP field) {
|
||||
super(field.get0().mutable(),
|
||||
field.get0().mutable(),
|
||||
field.get0().mutable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable conditionalSet(Point p, int set) {
|
||||
if (!(p instanceof ProjectivePoint)) {
|
||||
throw new RuntimeException("Incompatible point");
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ProjectivePoint<IntegerModuloP> pp =
|
||||
(ProjectivePoint<IntegerModuloP>) p;
|
||||
return conditionalSet(pp, set);
|
||||
}
|
||||
|
||||
private <T extends IntegerModuloP>
|
||||
Mutable conditionalSet(ProjectivePoint<T> pp, int set) {
|
||||
|
||||
x.conditionalSet(pp.x, set);
|
||||
y.conditionalSet(pp.y, set);
|
||||
z.conditionalSet(pp.z, set);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setValue(AffinePoint p) {
|
||||
x.setValue(p.getX());
|
||||
y.setValue(p.getY());
|
||||
z.setValue(p.getX().getField().get1());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setValue(Point p) {
|
||||
if (!(p instanceof ProjectivePoint)) {
|
||||
throw new RuntimeException("Incompatible point");
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ProjectivePoint<IntegerModuloP> pp =
|
||||
(ProjectivePoint<IntegerModuloP>) p;
|
||||
return setValue(pp);
|
||||
}
|
||||
|
||||
private <T extends IntegerModuloP>
|
||||
Mutable setValue(ProjectivePoint<T> pp) {
|
||||
|
||||
x.setValue(pp.x);
|
||||
y.setValue(pp.y);
|
||||
z.setValue(pp.z);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.interfaces;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* An SSL/TLS master secret key. It is a <code>SecretKey</code> that optionally
|
||||
* contains protocol version information that is used to detect version
|
||||
* rollback attacks during the SSL/TLS handshake.
|
||||
*
|
||||
* <p>Implementation of this interface are returned by the
|
||||
* <code>generateKey()</code> method of KeyGenerators of the type
|
||||
* "TlsMasterSecret".
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface TlsMasterSecret extends SecretKey {
|
||||
|
||||
public static final long serialVersionUID = -461748105810469773L;
|
||||
|
||||
/**
|
||||
* Returns the major version number encapsulated in the premaster secret
|
||||
* this master secret was derived from, or -1 if it is not available.
|
||||
*
|
||||
* <p>This information will only usually only be available when RSA
|
||||
* was used as the key exchange algorithm.
|
||||
*
|
||||
* @return the major version number, or -1 if it is not available
|
||||
*/
|
||||
public int getMajorVersion();
|
||||
|
||||
/**
|
||||
* Returns the minor version number encapsulated in the premaster secret
|
||||
* this master secret was derived from, or -1 if it is not available.
|
||||
*
|
||||
* <p>This information will only usually only be available when RSA
|
||||
* was used as the key exchange algorithm.
|
||||
*
|
||||
* @return the major version number, or -1 if it is not available
|
||||
*/
|
||||
public int getMinorVersion();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* Parameters for SSL/TLS key material generation.
|
||||
* This class is used to initialize KeyGenerator of the type
|
||||
* "TlsKeyMaterial". The keys returned by such KeyGenerators will be
|
||||
* instances of {@link TlsKeyMaterialSpec}.
|
||||
*
|
||||
* <p>Instances of this class are immutable.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private final SecretKey masterSecret;
|
||||
private final int majorVersion, minorVersion;
|
||||
private final byte[] clientRandom, serverRandom;
|
||||
private final String cipherAlgorithm;
|
||||
private final int cipherKeyLength, ivLength, macKeyLength;
|
||||
private final int expandedCipherKeyLength; // == 0 for domestic ciphersuites
|
||||
private final String prfHashAlg;
|
||||
private final int prfHashLength;
|
||||
private final int prfBlockSize;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsKeyMaterialParameterSpec.
|
||||
*
|
||||
* @param masterSecret the master secret
|
||||
* @param majorVersion the major number of the protocol version
|
||||
* @param minorVersion the minor number of the protocol version
|
||||
* @param clientRandom the client's random value
|
||||
* @param serverRandom the server's random value
|
||||
* @param cipherAlgorithm the algorithm name of the cipher keys to
|
||||
* be generated
|
||||
* @param cipherKeyLength if 0, no cipher keys will be generated;
|
||||
* otherwise, the length in bytes of cipher keys to be
|
||||
* generated for domestic cipher suites; for cipher suites defined as
|
||||
* exportable, the number of key material bytes to be generated;
|
||||
* @param expandedCipherKeyLength 0 for domestic cipher suites; for
|
||||
* exportable cipher suites the length in bytes of the key to be
|
||||
* generated.
|
||||
* @param ivLength the length in bytes of the initialization vector
|
||||
* to be generated, or 0 if no initialization vector is required
|
||||
* @param macKeyLength the length in bytes of the MAC key to be generated
|
||||
* @param prfHashAlg the name of the TLS PRF hash algorithm to use.
|
||||
* Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF.
|
||||
* @param prfHashLength the output length of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
* @param prfBlockSize the input block size of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
*
|
||||
* @throws NullPointerException if masterSecret, clientRandom,
|
||||
* serverRandom, or cipherAlgorithm are null
|
||||
* @throws IllegalArgumentException if the algorithm of masterSecret is
|
||||
* not TlsMasterSecret, or if majorVersion or minorVersion are
|
||||
* negative or larger than 255; or if cipherKeyLength, expandedKeyLength,
|
||||
* ivLength, or macKeyLength are negative
|
||||
*/
|
||||
public TlsKeyMaterialParameterSpec(SecretKey masterSecret,
|
||||
int majorVersion, int minorVersion, byte[] clientRandom,
|
||||
byte[] serverRandom, String cipherAlgorithm, int cipherKeyLength,
|
||||
int expandedCipherKeyLength, int ivLength, int macKeyLength,
|
||||
String prfHashAlg, int prfHashLength, int prfBlockSize) {
|
||||
if (masterSecret.getAlgorithm().equals("TlsMasterSecret") == false) {
|
||||
throw new IllegalArgumentException("Not a TLS master secret");
|
||||
}
|
||||
if (cipherAlgorithm == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.masterSecret = masterSecret;
|
||||
this.majorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(majorVersion);
|
||||
this.minorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(minorVersion);
|
||||
this.clientRandom = clientRandom.clone();
|
||||
this.serverRandom = serverRandom.clone();
|
||||
this.cipherAlgorithm = cipherAlgorithm;
|
||||
this.cipherKeyLength = checkSign(cipherKeyLength);
|
||||
this.expandedCipherKeyLength = checkSign(expandedCipherKeyLength);
|
||||
this.ivLength = checkSign(ivLength);
|
||||
this.macKeyLength = checkSign(macKeyLength);
|
||||
this.prfHashAlg = prfHashAlg;
|
||||
this.prfHashLength = prfHashLength;
|
||||
this.prfBlockSize = prfBlockSize;
|
||||
}
|
||||
|
||||
private static int checkSign(int k) {
|
||||
if (k < 0) {
|
||||
throw new IllegalArgumentException("Value must not be negative");
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the master secret.
|
||||
*
|
||||
* @return the master secret.
|
||||
*/
|
||||
public SecretKey getMasterSecret() {
|
||||
return masterSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the major version number.
|
||||
*
|
||||
* @return the major version number.
|
||||
*/
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor version number.
|
||||
*
|
||||
* @return the minor version number.
|
||||
*/
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the client's random value.
|
||||
*
|
||||
* @return a copy of the client's random value.
|
||||
*/
|
||||
public byte[] getClientRandom() {
|
||||
return clientRandom.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the server's random value.
|
||||
*
|
||||
* @return a copy of the server's random value.
|
||||
*/
|
||||
public byte[] getServerRandom() {
|
||||
return serverRandom.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cipher algorithm.
|
||||
*
|
||||
* @return the cipher algorithm.
|
||||
*/
|
||||
public String getCipherAlgorithm() {
|
||||
return cipherAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length in bytes of the encryption key to be generated.
|
||||
*
|
||||
* @return the length in bytes of the encryption key to be generated.
|
||||
*/
|
||||
public int getCipherKeyLength() {
|
||||
return cipherKeyLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length in bytes of the expanded encryption key to be
|
||||
* generated. Returns zero if the expanded encryption key is not
|
||||
* supposed to be generated.
|
||||
*
|
||||
* @return the length in bytes of the expanded encryption key to be
|
||||
* generated.
|
||||
*/
|
||||
public int getExpandedCipherKeyLength() {
|
||||
// TLS v1.1 disables the exportable weak cipher suites.
|
||||
if (majorVersion >= 0x03 && minorVersion >= 0x02) {
|
||||
return 0;
|
||||
}
|
||||
return expandedCipherKeyLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length in bytes of the initialization vector to be
|
||||
* generated. Returns zero if the initialization vector is not
|
||||
* supposed to be generated.
|
||||
*
|
||||
* @return the length in bytes of the initialization vector to be
|
||||
* generated.
|
||||
*/
|
||||
public int getIvLength() {
|
||||
return ivLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length in bytes of the MAC key to be generated.
|
||||
*
|
||||
* @return the length in bytes of the MAC key to be generated.
|
||||
*/
|
||||
public int getMacKeyLength() {
|
||||
return macKeyLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the PRF hash algorithm to use in the PRF calculation.
|
||||
*
|
||||
* @return the hash algorithm.
|
||||
*/
|
||||
public String getPRFHashAlg() {
|
||||
return prfHashAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the length of the PRF hash algorithm.
|
||||
*
|
||||
* @return the hash algorithm length.
|
||||
*/
|
||||
public int getPRFHashLength() {
|
||||
return prfHashLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the block size of the PRF hash algorithm.
|
||||
*
|
||||
* @return the hash algorithm block size
|
||||
*/
|
||||
public int getPRFBlockSize() {
|
||||
return prfBlockSize;
|
||||
}
|
||||
}
|
||||
191
jdkSrc/jdk8/sun/security/internal/spec/TlsKeyMaterialSpec.java
Normal file
191
jdkSrc/jdk8/sun/security/internal/spec/TlsKeyMaterialSpec.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.KeySpec;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
/**
|
||||
* KeySpec class for SSL/TLS key material.
|
||||
*
|
||||
* <p>Instances of this class are returned by the <code>generateKey()</code>
|
||||
* method of KeyGenerators of the type "TlsKeyMaterial".
|
||||
* Instances of this class are immutable.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
|
||||
static final long serialVersionUID = 812912859129525028L;
|
||||
|
||||
private final SecretKey clientMacKey, serverMacKey;
|
||||
private final SecretKey clientCipherKey, serverCipherKey;
|
||||
private final IvParameterSpec clientIv, serverIv;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsKeymaterialSpec from the client and server MAC
|
||||
* keys.
|
||||
* This call is equivalent to
|
||||
* <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey,
|
||||
* null, null, null, null)</code>.
|
||||
*
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey) {
|
||||
this(clientMacKey, serverMacKey, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TlsKeymaterialSpec from the client and server MAC
|
||||
* keys and client and server cipher keys.
|
||||
* This call is equivalent to
|
||||
* <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey,
|
||||
* clientCipherKey, serverCipherKey, null, null)</code>.
|
||||
*
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
* @param clientCipherKey the client cipher key (or null)
|
||||
* @param serverCipherKey the server cipher key (or null)
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey,
|
||||
SecretKey clientCipherKey, SecretKey serverCipherKey) {
|
||||
this(clientMacKey, serverMacKey, clientCipherKey, null,
|
||||
serverCipherKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TlsKeymaterialSpec from the client and server MAC
|
||||
* keys, client and server cipher keys, and client and server
|
||||
* initialization vectors.
|
||||
*
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
* @param clientCipherKey the client cipher key (or null)
|
||||
* @param clientIv the client initialization vector (or null)
|
||||
* @param serverCipherKey the server cipher key (or null)
|
||||
* @param serverIv the server initialization vector (or null)
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey,
|
||||
SecretKey clientCipherKey, IvParameterSpec clientIv,
|
||||
SecretKey serverCipherKey, IvParameterSpec serverIv) {
|
||||
|
||||
this.clientMacKey = clientMacKey;
|
||||
this.serverMacKey = serverMacKey;
|
||||
this.clientCipherKey = clientCipherKey;
|
||||
this.serverCipherKey = serverCipherKey;
|
||||
this.clientIv = clientIv;
|
||||
this.serverIv = serverIv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>TlsKeyMaterial</code>.
|
||||
*
|
||||
* @return <code>TlsKeyMaterial</code>.
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return "TlsKeyMaterial";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>null</code> because keys of this type have no encoding.
|
||||
*
|
||||
* @return <code>null</code> because keys of this type have no encoding.
|
||||
*/
|
||||
public String getFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>null</code> because keys of this type have no encoding.
|
||||
*
|
||||
* @return <code>null</code> because keys of this type have no encoding.
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client MAC key.
|
||||
*
|
||||
* @return the client MAC key (or null).
|
||||
*/
|
||||
public SecretKey getClientMacKey() {
|
||||
return clientMacKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server MAC key.
|
||||
*
|
||||
* @return the server MAC key (or null).
|
||||
*/
|
||||
public SecretKey getServerMacKey() {
|
||||
return serverMacKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client cipher key (or null).
|
||||
*
|
||||
* @return the client cipher key (or null).
|
||||
*/
|
||||
public SecretKey getClientCipherKey() {
|
||||
return clientCipherKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client initialization vector (or null).
|
||||
*
|
||||
* @return the client initialization vector (or null).
|
||||
*/
|
||||
public IvParameterSpec getClientIv() {
|
||||
return clientIv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server cipher key (or null).
|
||||
*
|
||||
* @return the server cipher key (or null).
|
||||
*/
|
||||
public SecretKey getServerCipherKey() {
|
||||
return serverCipherKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server initialization vector (or null).
|
||||
*
|
||||
* @return the server initialization vector (or null).
|
||||
*/
|
||||
public IvParameterSpec getServerIv() {
|
||||
return serverIv;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* Parameters for SSL/TLS master secret generation.
|
||||
* This class encapsulates the information necessary to calculate a SSL/TLS
|
||||
* master secret from the premaster secret and other parameters.
|
||||
* It is used to initialize KeyGenerators of the type "TlsMasterSecret".
|
||||
*
|
||||
* <p>Instances of this class are immutable.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private final SecretKey premasterSecret;
|
||||
private final int majorVersion, minorVersion;
|
||||
private final byte[] clientRandom, serverRandom;
|
||||
private final byte[] extendedMasterSecretSessionHash;
|
||||
private final String prfHashAlg;
|
||||
private final int prfHashLength;
|
||||
private final int prfBlockSize;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsMasterSecretParameterSpec.
|
||||
*
|
||||
* <p>The <code>getAlgorithm()</code> method of <code>premasterSecret</code>
|
||||
* should return <code>"TlsRsaPremasterSecret"</code> if the key exchange
|
||||
* algorithm was RSA and <code>"TlsPremasterSecret"</code> otherwise.
|
||||
*
|
||||
* @param premasterSecret the premaster secret
|
||||
* @param majorVersion the major number of the protocol version
|
||||
* @param minorVersion the minor number of the protocol version
|
||||
* @param clientRandom the client's random value
|
||||
* @param serverRandom the server's random value
|
||||
* @param prfHashAlg the name of the TLS PRF hash algorithm to use.
|
||||
* Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF.
|
||||
* @param prfHashLength the output length of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
* @param prfBlockSize the input block size of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
*
|
||||
* @throws NullPointerException if premasterSecret, clientRandom,
|
||||
* or serverRandom are null
|
||||
* @throws IllegalArgumentException if minorVersion or majorVersion are
|
||||
* negative or larger than 255
|
||||
*/
|
||||
public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
|
||||
int majorVersion, int minorVersion,
|
||||
byte[] clientRandom, byte[] serverRandom,
|
||||
String prfHashAlg, int prfHashLength, int prfBlockSize) {
|
||||
this(premasterSecret, majorVersion, minorVersion,
|
||||
clientRandom, serverRandom,
|
||||
new byte[0],
|
||||
prfHashAlg, prfHashLength, prfBlockSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TlsMasterSecretParameterSpec.
|
||||
*
|
||||
* <p>The <code>getAlgorithm()</code> method of <code>premasterSecret</code>
|
||||
* should return <code>"TlsRsaPremasterSecret"</code> if the key exchange
|
||||
* algorithm was RSA and <code>"TlsPremasterSecret"</code> otherwise.
|
||||
*
|
||||
* @param premasterSecret the premaster secret
|
||||
* @param majorVersion the major number of the protocol version
|
||||
* @param minorVersion the minor number of the protocol version
|
||||
* @param extendedMasterSecretSessionHash the session hash for
|
||||
* Extended Master Secret
|
||||
* @param prfHashAlg the name of the TLS PRF hash algorithm to use.
|
||||
* Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF.
|
||||
* @param prfHashLength the output length of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
* @param prfBlockSize the input block size of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
*
|
||||
* @throws NullPointerException if premasterSecret is null
|
||||
* @throws IllegalArgumentException if minorVersion or majorVersion are
|
||||
* negative or larger than 255
|
||||
*/
|
||||
public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
|
||||
int majorVersion, int minorVersion,
|
||||
byte[] extendedMasterSecretSessionHash,
|
||||
String prfHashAlg, int prfHashLength, int prfBlockSize) {
|
||||
this(premasterSecret, majorVersion, minorVersion,
|
||||
new byte[0], new byte[0],
|
||||
extendedMasterSecretSessionHash,
|
||||
prfHashAlg, prfHashLength, prfBlockSize);
|
||||
}
|
||||
|
||||
private TlsMasterSecretParameterSpec(SecretKey premasterSecret,
|
||||
int majorVersion, int minorVersion,
|
||||
byte[] clientRandom, byte[] serverRandom,
|
||||
byte[] extendedMasterSecretSessionHash,
|
||||
String prfHashAlg, int prfHashLength, int prfBlockSize) {
|
||||
if (premasterSecret == null) {
|
||||
throw new NullPointerException("premasterSecret must not be null");
|
||||
}
|
||||
this.premasterSecret = premasterSecret;
|
||||
this.majorVersion = checkVersion(majorVersion);
|
||||
this.minorVersion = checkVersion(minorVersion);
|
||||
this.clientRandom = clientRandom.clone();
|
||||
this.serverRandom = serverRandom.clone();
|
||||
this.extendedMasterSecretSessionHash =
|
||||
(extendedMasterSecretSessionHash != null ?
|
||||
extendedMasterSecretSessionHash.clone() : new byte[0]);
|
||||
this.prfHashAlg = prfHashAlg;
|
||||
this.prfHashLength = prfHashLength;
|
||||
this.prfBlockSize = prfBlockSize;
|
||||
}
|
||||
|
||||
static int checkVersion(int version) {
|
||||
if ((version < 0) || (version > 255)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Version must be between 0 and 255");
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the premaster secret.
|
||||
*
|
||||
* @return the premaster secret.
|
||||
*/
|
||||
public SecretKey getPremasterSecret() {
|
||||
return premasterSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the major version number.
|
||||
*
|
||||
* @return the major version number.
|
||||
*/
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor version number.
|
||||
*
|
||||
* @return the minor version number.
|
||||
*/
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the client's random value.
|
||||
*
|
||||
* @return a copy of the client's random value.
|
||||
*/
|
||||
public byte[] getClientRandom() {
|
||||
return clientRandom.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the server's random value.
|
||||
*
|
||||
* @return a copy of the server's random value.
|
||||
*/
|
||||
public byte[] getServerRandom() {
|
||||
return serverRandom.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the Extended Master Secret session hash.
|
||||
*
|
||||
* @return a copy of the Extended Master Secret session hash, or an empty
|
||||
* array if no extended master secret session hash was provided
|
||||
* at instantiation time
|
||||
*/
|
||||
public byte[] getExtendedMasterSecretSessionHash() {
|
||||
return extendedMasterSecretSessionHash.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the PRF hash algorithm to use in the PRF calculation.
|
||||
*
|
||||
* @return the hash algorithm.
|
||||
*/
|
||||
public String getPRFHashAlg() {
|
||||
return prfHashAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the length of the PRF hash algorithm.
|
||||
*
|
||||
* @return the hash algorithm length.
|
||||
*/
|
||||
public int getPRFHashLength() {
|
||||
return prfHashLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the block size of the PRF hash algorithm.
|
||||
*
|
||||
* @return the hash algorithm block size.
|
||||
*/
|
||||
public int getPRFBlockSize() {
|
||||
return prfBlockSize;
|
||||
}
|
||||
}
|
||||
157
jdkSrc/jdk8/sun/security/internal/spec/TlsPrfParameterSpec.java
Normal file
157
jdkSrc/jdk8/sun/security/internal/spec/TlsPrfParameterSpec.java
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* Parameters for the TLS PRF (pseudo-random function). The PRF function
|
||||
* is defined in RFC 2246.
|
||||
* This class is used to initialize KeyGenerators of the type "TlsPrf".
|
||||
*
|
||||
* <p>Instances of this class are immutable.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsPrfParameterSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private final SecretKey secret;
|
||||
private final String label;
|
||||
private final byte[] seed;
|
||||
private final int outputLength;
|
||||
private final String prfHashAlg;
|
||||
private final int prfHashLength;
|
||||
private final int prfBlockSize;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsPrfParameterSpec.
|
||||
*
|
||||
* @param secret the secret to use in the calculation (or null)
|
||||
* @param label the label to use in the calculation
|
||||
* @param seed the random seed to use in the calculation
|
||||
* @param outputLength the length in bytes of the output key to be produced
|
||||
* @param prfHashAlg the name of the TLS PRF hash algorithm to use.
|
||||
* Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF.
|
||||
* @param prfHashLength the output length of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
* @param prfBlockSize the input block size of the TLS PRF hash algorithm.
|
||||
* Used only for TLS 1.2+.
|
||||
*
|
||||
* @throws NullPointerException if label or seed is null
|
||||
* @throws IllegalArgumentException if outputLength is negative
|
||||
*/
|
||||
public TlsPrfParameterSpec(SecretKey secret, String label,
|
||||
byte[] seed, int outputLength,
|
||||
String prfHashAlg, int prfHashLength, int prfBlockSize) {
|
||||
if ((label == null) || (seed == null)) {
|
||||
throw new NullPointerException("label and seed must not be null");
|
||||
}
|
||||
if (outputLength <= 0) {
|
||||
throw new IllegalArgumentException("outputLength must be positive");
|
||||
}
|
||||
this.secret = secret;
|
||||
this.label = label;
|
||||
this.seed = seed.clone();
|
||||
this.outputLength = outputLength;
|
||||
this.prfHashAlg = prfHashAlg;
|
||||
this.prfHashLength = prfHashLength;
|
||||
this.prfBlockSize = prfBlockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the secret to use in the PRF calculation, or null if there is no
|
||||
* secret.
|
||||
*
|
||||
* @return the secret to use in the PRF calculation, or null if there is no
|
||||
* secret.
|
||||
*/
|
||||
public SecretKey getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label to use in the PRF calcuation.
|
||||
*
|
||||
* @return the label to use in the PRF calcuation.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the seed to use in the PRF calcuation.
|
||||
*
|
||||
* @return a copy of the seed to use in the PRF calcuation.
|
||||
*/
|
||||
public byte[] getSeed() {
|
||||
return seed.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length in bytes of the output key to be produced.
|
||||
*
|
||||
* @return the length in bytes of the output key to be produced.
|
||||
*/
|
||||
public int getOutputLength() {
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the PRF hash algorithm to use in the PRF calculation.
|
||||
*
|
||||
* @return the hash algorithm, or null if no algorithm was specified.
|
||||
*/
|
||||
public String getPRFHashAlg() {
|
||||
return prfHashAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the length of PRF hash algorithm.
|
||||
*
|
||||
* It would have been preferred to use MessageDigest.getDigestLength(),
|
||||
* but the API does not require implementations to support the method.
|
||||
*
|
||||
* @return the hash algorithm length.
|
||||
*/
|
||||
public int getPRFHashLength() {
|
||||
return prfHashLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the length of PRF hash algorithm.
|
||||
*
|
||||
* @return the hash algorithm length.
|
||||
*/
|
||||
public int getPRFBlockSize() {
|
||||
return prfBlockSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Parameters for SSL/TLS RSA premaster secret.
|
||||
*
|
||||
* <p>Instances of this class are immutable.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsRsaPremasterSecretParameterSpec
|
||||
implements AlgorithmParameterSpec {
|
||||
|
||||
private final byte[] encodedSecret;
|
||||
|
||||
/*
|
||||
* The TLS spec says that the version in the RSA premaster secret must
|
||||
* be the maximum version supported by the client (i.e. the version it
|
||||
* requested in its client hello version). However, we (and other
|
||||
* implementations) used to send the active negotiated version. The
|
||||
* system property below allows to toggle the behavior.
|
||||
*/
|
||||
private final static String PROP_NAME =
|
||||
"com.sun.net.ssl.rsaPreMasterSecretFix";
|
||||
|
||||
/*
|
||||
* Default is "false" (old behavior) for compatibility reasons in
|
||||
* SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property.
|
||||
*/
|
||||
private final static boolean rsaPreMasterSecretFix =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
String value = System.getProperty(PROP_NAME);
|
||||
if (value != null && value.equalsIgnoreCase("true")) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
});
|
||||
|
||||
private final int clientVersion;
|
||||
private final int serverVersion;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsRsaPremasterSecretParameterSpec.
|
||||
*
|
||||
* @param clientVersion the version of the TLS protocol by which the
|
||||
* client wishes to communicate during this session
|
||||
* @param serverVersion the negotiated version of the TLS protocol which
|
||||
* contains the lower of that suggested by the client in the client
|
||||
* hello and the highest supported by the server.
|
||||
*
|
||||
* @throws IllegalArgumentException if clientVersion or serverVersion are
|
||||
* negative or larger than (2^16 - 1)
|
||||
*/
|
||||
public TlsRsaPremasterSecretParameterSpec(
|
||||
int clientVersion, int serverVersion) {
|
||||
|
||||
this.clientVersion = checkVersion(clientVersion);
|
||||
this.serverVersion = checkVersion(serverVersion);
|
||||
this.encodedSecret = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TlsRsaPremasterSecretParameterSpec.
|
||||
*
|
||||
* @param clientVersion the version of the TLS protocol by which the
|
||||
* client wishes to communicate during this session
|
||||
* @param serverVersion the negotiated version of the TLS protocol which
|
||||
* contains the lower of that suggested by the client in the client
|
||||
* hello and the highest supported by the server.
|
||||
* @param encodedSecret the encoded secret key
|
||||
*
|
||||
* @throws IllegalArgumentException if clientVersion or serverVersion are
|
||||
* negative or larger than (2^16 - 1) or if encodedSecret is not
|
||||
* exactly 48 bytes
|
||||
*/
|
||||
public TlsRsaPremasterSecretParameterSpec(
|
||||
int clientVersion, int serverVersion, byte[] encodedSecret) {
|
||||
|
||||
this.clientVersion = checkVersion(clientVersion);
|
||||
this.serverVersion = checkVersion(serverVersion);
|
||||
if (encodedSecret == null || encodedSecret.length != 48) {
|
||||
throw new IllegalArgumentException(
|
||||
"Encoded secret is not exactly 48 bytes");
|
||||
}
|
||||
this.encodedSecret = encodedSecret.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the TLS protocol by which the client wishes to
|
||||
* communicate during this session.
|
||||
*
|
||||
* @return the version of the TLS protocol in ClientHello message
|
||||
*/
|
||||
public int getClientVersion() {
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negotiated version of the TLS protocol which contains the
|
||||
* lower of that suggested by the client in the client hello and the
|
||||
* highest supported by the server.
|
||||
*
|
||||
* @return the negotiated version of the TLS protocol in ServerHello message
|
||||
*/
|
||||
public int getServerVersion() {
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the major version used in RSA premaster secret.
|
||||
*
|
||||
* @return the major version used in RSA premaster secret.
|
||||
*/
|
||||
public int getMajorVersion() {
|
||||
if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
|
||||
// 0x0302: TLSv1.1
|
||||
return (clientVersion >>> 8) & 0xFF;
|
||||
}
|
||||
|
||||
return (serverVersion >>> 8) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor version used in RSA premaster secret.
|
||||
*
|
||||
* @return the minor version used in RSA premaster secret.
|
||||
*/
|
||||
public int getMinorVersion() {
|
||||
if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
|
||||
// 0x0302: TLSv1.1
|
||||
return clientVersion & 0xFF;
|
||||
}
|
||||
|
||||
return serverVersion & 0xFF;
|
||||
}
|
||||
|
||||
private int checkVersion(int version) {
|
||||
if ((version < 0) || (version > 0xFFFF)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Version must be between 0 and 65,535");
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded secret.
|
||||
*
|
||||
* @return the encoded secret, may be null if no encoded secret.
|
||||
*/
|
||||
public byte[] getEncodedSecret() {
|
||||
return encodedSecret == null ? null : encodedSecret.clone();
|
||||
}
|
||||
}
|
||||
264
jdkSrc/jdk8/sun/security/jca/GetInstance.java
Normal file
264
jdkSrc/jdk8/sun/security/jca/GetInstance.java
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.Provider.Service;
|
||||
|
||||
/**
|
||||
* Collection of utility methods to facilitate implementing getInstance()
|
||||
* methods in the JCA/JCE/JSSE/... framework.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public class GetInstance {
|
||||
|
||||
private GetInstance() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Static inner class representing a newly created instance.
|
||||
*/
|
||||
public static final class Instance {
|
||||
// public final fields, access directly without accessors
|
||||
public final Provider provider;
|
||||
public final Object impl;
|
||||
private Instance(Provider provider, Object impl) {
|
||||
this.provider = provider;
|
||||
this.impl = impl;
|
||||
}
|
||||
// Return Provider and implementation as an array as used in the
|
||||
// old Security.getImpl() methods.
|
||||
public Object[] toArray() {
|
||||
return new Object[] {impl, provider};
|
||||
}
|
||||
}
|
||||
|
||||
public static Service getService(String type, String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
ProviderList list = Providers.getProviderList();
|
||||
Service s = list.getService(type, algorithm);
|
||||
if (s == null) {
|
||||
throw new NoSuchAlgorithmException
|
||||
(algorithm + " " + type + " not available");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Service getService(String type, String algorithm,
|
||||
String provider) throws NoSuchAlgorithmException,
|
||||
NoSuchProviderException {
|
||||
if ((provider == null) || (provider.length() == 0)) {
|
||||
throw new IllegalArgumentException("missing provider");
|
||||
}
|
||||
Provider p = Providers.getProviderList().getProvider(provider);
|
||||
if (p == null) {
|
||||
throw new NoSuchProviderException("no such provider: " + provider);
|
||||
}
|
||||
Service s = p.getService(type, algorithm);
|
||||
if (s == null) {
|
||||
throw new NoSuchAlgorithmException("no such algorithm: "
|
||||
+ algorithm + " for provider " + provider);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Service getService(String type, String algorithm,
|
||||
Provider provider) throws NoSuchAlgorithmException {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("missing provider");
|
||||
}
|
||||
Service s = provider.getService(type, algorithm);
|
||||
if (s == null) {
|
||||
throw new NoSuchAlgorithmException("no such algorithm: "
|
||||
+ algorithm + " for provider " + provider.getName());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a List of all the available Services that implement
|
||||
* (type, algorithm). Note that the list is initialized lazily
|
||||
* and Provider loading and lookup is only trigered when
|
||||
* necessary.
|
||||
*/
|
||||
public static List<Service> getServices(String type, String algorithm) {
|
||||
ProviderList list = Providers.getProviderList();
|
||||
return list.getServices(type, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method exists for compatibility with JCE only. It will be removed
|
||||
* once JCE has been changed to use the replacement method.
|
||||
* @deprecated use getServices(List<ServiceId>) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<Service> getServices(String type,
|
||||
List<String> algorithms) {
|
||||
ProviderList list = Providers.getProviderList();
|
||||
return list.getServices(type, algorithms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a List of all the available Services that implement any of
|
||||
* the specified algorithms. See getServices(String, String) for detals.
|
||||
*/
|
||||
public static List<Service> getServices(List<ServiceId> ids) {
|
||||
ProviderList list = Providers.getProviderList();
|
||||
return list.getServices(ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* For all the getInstance() methods below:
|
||||
* @param type the type of engine (e.g. MessageDigest)
|
||||
* @param clazz the Spi class that the implementation must subclass
|
||||
* (e.g. MessageDigestSpi.class) or null if no superclass check
|
||||
* is required
|
||||
* @param algorithm the name of the algorithm (or alias), e.g. MD5
|
||||
* @param provider the provider (String or Provider object)
|
||||
* @param param the parameter to pass to the Spi constructor
|
||||
* (for CertStores)
|
||||
*
|
||||
* There are overloaded methods for all the permutations.
|
||||
*/
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm) throws NoSuchAlgorithmException {
|
||||
// in the almost all cases, the first service will work
|
||||
// avoid taking long path if so
|
||||
ProviderList list = Providers.getProviderList();
|
||||
Service firstService = list.getService(type, algorithm);
|
||||
if (firstService == null) {
|
||||
throw new NoSuchAlgorithmException
|
||||
(algorithm + " " + type + " not available");
|
||||
}
|
||||
NoSuchAlgorithmException failure;
|
||||
try {
|
||||
return getInstance(firstService, clazz);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
failure = e;
|
||||
}
|
||||
// if we cannot get the service from the preferred provider,
|
||||
// fail over to the next
|
||||
for (Service s : list.getServices(type, algorithm)) {
|
||||
if (s == firstService) {
|
||||
// do not retry initial failed service
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
return getInstance(s, clazz);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
failure = e;
|
||||
}
|
||||
}
|
||||
throw failure;
|
||||
}
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm, Object param) throws NoSuchAlgorithmException {
|
||||
List<Service> services = getServices(type, algorithm);
|
||||
NoSuchAlgorithmException failure = null;
|
||||
for (Service s : services) {
|
||||
try {
|
||||
return getInstance(s, clazz, param);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
failure = e;
|
||||
}
|
||||
}
|
||||
if (failure != null) {
|
||||
throw failure;
|
||||
} else {
|
||||
throw new NoSuchAlgorithmException
|
||||
(algorithm + " " + type + " not available");
|
||||
}
|
||||
}
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm, String provider) throws NoSuchAlgorithmException,
|
||||
NoSuchProviderException {
|
||||
return getInstance(getService(type, algorithm, provider), clazz);
|
||||
}
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm, Object param, String provider)
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
return getInstance(getService(type, algorithm, provider), clazz, param);
|
||||
}
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm, Provider provider)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getInstance(getService(type, algorithm, provider), clazz);
|
||||
}
|
||||
|
||||
public static Instance getInstance(String type, Class<?> clazz,
|
||||
String algorithm, Object param, Provider provider)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getInstance(getService(type, algorithm, provider), clazz, param);
|
||||
}
|
||||
|
||||
/*
|
||||
* The two getInstance() methods below take a service. They are
|
||||
* intended for classes that cannot use the standard methods, e.g.
|
||||
* because they implement delayed provider selection like the
|
||||
* Signature class.
|
||||
*/
|
||||
|
||||
public static Instance getInstance(Service s, Class<?> clazz)
|
||||
throws NoSuchAlgorithmException {
|
||||
Object instance = s.newInstance(null);
|
||||
checkSuperClass(s, instance.getClass(), clazz);
|
||||
return new Instance(s.getProvider(), instance);
|
||||
}
|
||||
|
||||
public static Instance getInstance(Service s, Class<?> clazz,
|
||||
Object param) throws NoSuchAlgorithmException {
|
||||
Object instance = s.newInstance(param);
|
||||
checkSuperClass(s, instance.getClass(), clazz);
|
||||
return new Instance(s.getProvider(), instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is subClass is a subclass of superClass. If not,
|
||||
* throw a NoSuchAlgorithmException.
|
||||
*/
|
||||
public static void checkSuperClass(Service s, Class<?> subClass,
|
||||
Class<?> superClass) throws NoSuchAlgorithmException {
|
||||
if (superClass == null) {
|
||||
return;
|
||||
}
|
||||
if (superClass.isAssignableFrom(subClass) == false) {
|
||||
throw new NoSuchAlgorithmException
|
||||
("class configured for " + s.getType() + ": "
|
||||
+ s.getClassName() + " not a " + s.getType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
72
jdkSrc/jdk8/sun/security/jca/JCAUtil.java
Normal file
72
jdkSrc/jdk8/sun/security/jca/JCAUtil.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
import java.lang.ref.*;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* Collection of static utility methods used by the security framework.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class JCAUtil {
|
||||
|
||||
private JCAUtil() {
|
||||
// no instantiation
|
||||
}
|
||||
|
||||
// size of the temporary arrays we use. Should fit into the CPU's 1st
|
||||
// level cache and could be adjusted based on the platform
|
||||
private final static int ARRAY_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Get the size of a temporary buffer array to use in order to be
|
||||
* cache efficient. totalSize indicates the total amount of data to
|
||||
* be buffered. Used by the engineUpdate(ByteBuffer) methods.
|
||||
*/
|
||||
public static int getTempArraySize(int totalSize) {
|
||||
return Math.min(ARRAY_SIZE, totalSize);
|
||||
}
|
||||
|
||||
// cached SecureRandom instance
|
||||
private static class CachedSecureRandomHolder {
|
||||
public static SecureRandom instance = new SecureRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a SecureRandom instance. This method should be used by JDK
|
||||
* internal code in favor of calling "new SecureRandom()". That needs to
|
||||
* iterate through the provider table to find the default SecureRandom
|
||||
* implementation, which is fairly inefficient.
|
||||
*/
|
||||
public static SecureRandom getSecureRandom() {
|
||||
return CachedSecureRandomHolder.instance;
|
||||
}
|
||||
|
||||
}
|
||||
293
jdkSrc/jdk8/sun/security/jca/ProviderConfig.java
Normal file
293
jdkSrc/jdk8/sun/security/jca/ProviderConfig.java
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
import sun.security.util.PropertyExpander;
|
||||
|
||||
/**
|
||||
* Class representing a configured provider. Encapsulates configuration
|
||||
* (className plus optional argument), the provider loading logic, and
|
||||
* the loaded Provider object itself.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
final class ProviderConfig {
|
||||
|
||||
private final static sun.security.util.Debug debug =
|
||||
sun.security.util.Debug.getInstance("jca", "ProviderConfig");
|
||||
|
||||
// classname of the SunPKCS11-Solaris provider
|
||||
private static final String P11_SOL_NAME =
|
||||
"sun.security.pkcs11.SunPKCS11";
|
||||
|
||||
// config file argument of the SunPKCS11-Solaris provider
|
||||
private static final String P11_SOL_ARG =
|
||||
"${java.home}/lib/security/sunpkcs11-solaris.cfg";
|
||||
|
||||
// maximum number of times to try loading a provider before giving up
|
||||
private final static int MAX_LOAD_TRIES = 30;
|
||||
|
||||
// parameters for the Provider(String) constructor,
|
||||
// use by doLoadProvider()
|
||||
private final static Class[] CL_STRING = { String.class };
|
||||
|
||||
// name of the provider class
|
||||
private final String className;
|
||||
|
||||
// argument to the provider constructor,
|
||||
// empty string indicates no-arg constructor
|
||||
private final String argument;
|
||||
|
||||
// number of times we have already tried to load this provider
|
||||
private int tries;
|
||||
|
||||
// Provider object, if loaded
|
||||
private volatile Provider provider;
|
||||
|
||||
// flag indicating if we are currently trying to load the provider
|
||||
// used to detect recursion
|
||||
private boolean isLoading;
|
||||
|
||||
ProviderConfig(String className, String argument) {
|
||||
if (className.equals(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {
|
||||
checkSunPKCS11Solaris();
|
||||
}
|
||||
this.className = className;
|
||||
this.argument = expand(argument);
|
||||
}
|
||||
|
||||
ProviderConfig(String className) {
|
||||
this(className, "");
|
||||
}
|
||||
|
||||
ProviderConfig(Provider provider) {
|
||||
this.className = provider.getClass().getName();
|
||||
this.argument = "";
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
// check if we should try to load the SunPKCS11-Solaris provider
|
||||
// avoid if not available (pre Solaris 10) to reduce startup time
|
||||
// or if disabled via system property
|
||||
private void checkSunPKCS11Solaris() {
|
||||
Boolean o = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
File file = new File("/usr/lib/libpkcs11.so");
|
||||
if (file.exists() == false) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if ("false".equalsIgnoreCase(System.getProperty
|
||||
("sun.security.pkcs11.enable-solaris"))) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
});
|
||||
if (o == Boolean.FALSE) {
|
||||
tries = MAX_LOAD_TRIES;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasArgument() {
|
||||
return argument.length() != 0;
|
||||
}
|
||||
|
||||
// should we try to load this provider?
|
||||
private boolean shouldLoad() {
|
||||
return (tries < MAX_LOAD_TRIES);
|
||||
}
|
||||
|
||||
// do not try to load this provider again
|
||||
private void disableLoad() {
|
||||
tries = MAX_LOAD_TRIES;
|
||||
}
|
||||
|
||||
boolean isLoaded() {
|
||||
return (provider != null);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ProviderConfig == false) {
|
||||
return false;
|
||||
}
|
||||
ProviderConfig other = (ProviderConfig)obj;
|
||||
return this.className.equals(other.className)
|
||||
&& this.argument.equals(other.argument);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return className.hashCode() + argument.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (hasArgument()) {
|
||||
return className + "('" + argument + "')";
|
||||
} else {
|
||||
return className;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the provider object. Loads the provider if it is not already loaded.
|
||||
*/
|
||||
synchronized Provider getProvider() {
|
||||
// volatile variable load
|
||||
Provider p = provider;
|
||||
if (p != null) {
|
||||
return p;
|
||||
}
|
||||
if (shouldLoad() == false) {
|
||||
return null;
|
||||
}
|
||||
if (isLoading) {
|
||||
// because this method is synchronized, this can only
|
||||
// happen if there is recursion.
|
||||
if (debug != null) {
|
||||
debug.println("Recursion loading provider: " + this);
|
||||
new Exception("Call trace").printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
isLoading = true;
|
||||
tries++;
|
||||
p = doLoadProvider();
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
provider = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and instantiate the Provider described by this class.
|
||||
*
|
||||
* NOTE use of doPrivileged().
|
||||
*
|
||||
* @return null if the Provider could not be loaded
|
||||
*
|
||||
* @throws ProviderException if executing the Provider's constructor
|
||||
* throws a ProviderException. All other Exceptions are ignored.
|
||||
*/
|
||||
private Provider doLoadProvider() {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
|
||||
public Provider run() {
|
||||
if (debug != null) {
|
||||
debug.println("Loading provider: " + ProviderConfig.this);
|
||||
}
|
||||
try {
|
||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||
Class<?> provClass;
|
||||
if (cl != null) {
|
||||
provClass = cl.loadClass(className);
|
||||
} else {
|
||||
provClass = Class.forName(className);
|
||||
}
|
||||
Object obj;
|
||||
if (hasArgument() == false) {
|
||||
obj = provClass.newInstance();
|
||||
} else {
|
||||
Constructor<?> cons = provClass.getConstructor(CL_STRING);
|
||||
obj = cons.newInstance(argument);
|
||||
}
|
||||
if (obj instanceof Provider) {
|
||||
if (debug != null) {
|
||||
debug.println("Loaded provider " + obj);
|
||||
}
|
||||
return (Provider)obj;
|
||||
} else {
|
||||
if (debug != null) {
|
||||
debug.println(className + " is not a provider");
|
||||
}
|
||||
disableLoad();
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwable t;
|
||||
if (e instanceof InvocationTargetException) {
|
||||
t = ((InvocationTargetException)e).getCause();
|
||||
} else {
|
||||
t = e;
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Error loading provider " + ProviderConfig.this);
|
||||
t.printStackTrace();
|
||||
}
|
||||
// provider indicates fatal error, pass through exception
|
||||
if (t instanceof ProviderException) {
|
||||
throw (ProviderException)t;
|
||||
}
|
||||
// provider indicates that loading should not be retried
|
||||
if (t instanceof UnsupportedOperationException) {
|
||||
disableLoad();
|
||||
}
|
||||
return null;
|
||||
} catch (ExceptionInInitializerError err) {
|
||||
// unexpected exception thrown from static initialization block in provider
|
||||
// (ex: insufficient permission to initialize provider class)
|
||||
if (debug != null) {
|
||||
debug.println("Error loading provider " + ProviderConfig.this);
|
||||
err.printStackTrace();
|
||||
}
|
||||
disableLoad();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform property expansion of the provider value.
|
||||
*
|
||||
* NOTE use of doPrivileged().
|
||||
*/
|
||||
private static String expand(final String value) {
|
||||
// shortcut if value does not contain any properties
|
||||
if (value.contains("${") == false) {
|
||||
return value;
|
||||
}
|
||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
try {
|
||||
return PropertyExpander.expand(value);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
505
jdkSrc/jdk8/sun/security/jca/ProviderList.java
Normal file
505
jdkSrc/jdk8/sun/security/jca/ProviderList.java
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.Provider.Service;
|
||||
|
||||
/**
|
||||
* List of Providers. Used to represent the provider preferences.
|
||||
*
|
||||
* The system starts out with a ProviderList that only has the classNames
|
||||
* of the Providers. Providers are loaded on demand only when needed.
|
||||
*
|
||||
* For compatibility reasons, Providers that could not be loaded are ignored
|
||||
* and internally presented as the instance EMPTY_PROVIDER. However, those
|
||||
* objects cannot be presented to applications. Call the convert() method
|
||||
* to force all Providers to be loaded and to obtain a ProviderList with
|
||||
* invalid entries removed. All this is handled by the Security class.
|
||||
*
|
||||
* Note that all indices used by this class are 0-based per general Java
|
||||
* convention. These must be converted to the 1-based indices used by the
|
||||
* Security class externally when needed.
|
||||
*
|
||||
* Instances of this class are immutable. This eliminates the need for
|
||||
* cloning and synchronization in consumers. The add() and remove() style
|
||||
* methods are static in order to avoid confusion about the immutability.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class ProviderList {
|
||||
|
||||
final static sun.security.util.Debug debug =
|
||||
sun.security.util.Debug.getInstance("jca", "ProviderList");
|
||||
|
||||
private final static ProviderConfig[] PC0 = new ProviderConfig[0];
|
||||
|
||||
private final static Provider[] P0 = new Provider[0];
|
||||
|
||||
// constant for an ProviderList with no elements
|
||||
static final ProviderList EMPTY = new ProviderList(PC0, true);
|
||||
|
||||
// dummy provider object to use during initialization
|
||||
// used to avoid explicit null checks in various places
|
||||
private static final Provider EMPTY_PROVIDER =
|
||||
new Provider("##Empty##", 1.0d, "initialization in progress") {
|
||||
private static final long serialVersionUID = 1151354171352296389L;
|
||||
// override getService() to return null slightly faster
|
||||
public Service getService(String type, String algorithm) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// construct a ProviderList from the security properties
|
||||
// (static provider configuration in the java.security file)
|
||||
static ProviderList fromSecurityProperties() {
|
||||
// doPrivileged() because of Security.getProperty()
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<ProviderList>() {
|
||||
public ProviderList run() {
|
||||
return new ProviderList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ProviderList add(ProviderList providerList, Provider p) {
|
||||
return insertAt(providerList, p, -1);
|
||||
}
|
||||
|
||||
public static ProviderList insertAt(ProviderList providerList, Provider p,
|
||||
int position) {
|
||||
if (providerList.getProvider(p.getName()) != null) {
|
||||
return providerList;
|
||||
}
|
||||
List<ProviderConfig> list = new ArrayList<>
|
||||
(Arrays.asList(providerList.configs));
|
||||
int n = list.size();
|
||||
if ((position < 0) || (position > n)) {
|
||||
position = n;
|
||||
}
|
||||
list.add(position, new ProviderConfig(p));
|
||||
return new ProviderList(list.toArray(PC0), true);
|
||||
}
|
||||
|
||||
public static ProviderList remove(ProviderList providerList, String name) {
|
||||
// make sure provider exists
|
||||
if (providerList.getProvider(name) == null) {
|
||||
return providerList;
|
||||
}
|
||||
// copy all except matching to new list
|
||||
ProviderConfig[] configs = new ProviderConfig[providerList.size() - 1];
|
||||
int j = 0;
|
||||
for (ProviderConfig config : providerList.configs) {
|
||||
if (config.getProvider().getName().equals(name) == false) {
|
||||
configs[j++] = config;
|
||||
}
|
||||
}
|
||||
return new ProviderList(configs, true);
|
||||
}
|
||||
|
||||
// Create a new ProviderList from the specified Providers.
|
||||
// This method is for use by SunJSSE.
|
||||
public static ProviderList newList(Provider ... providers) {
|
||||
ProviderConfig[] configs = new ProviderConfig[providers.length];
|
||||
for (int i = 0; i < providers.length; i++) {
|
||||
configs[i] = new ProviderConfig(providers[i]);
|
||||
}
|
||||
return new ProviderList(configs, true);
|
||||
}
|
||||
|
||||
// configuration of the providers
|
||||
private final ProviderConfig[] configs;
|
||||
|
||||
// flag indicating whether all configs have been loaded successfully
|
||||
private volatile boolean allLoaded;
|
||||
|
||||
// List returned by providers()
|
||||
private final List<Provider> userList = new AbstractList<Provider>() {
|
||||
public int size() {
|
||||
return configs.length;
|
||||
}
|
||||
public Provider get(int index) {
|
||||
return getProvider(index);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ProviderList from an array of configs
|
||||
*/
|
||||
private ProviderList(ProviderConfig[] configs, boolean allLoaded) {
|
||||
this.configs = configs;
|
||||
this.allLoaded = allLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new ProviderList parsed from the java.security Properties.
|
||||
*/
|
||||
private ProviderList() {
|
||||
List<ProviderConfig> configList = new ArrayList<>();
|
||||
for (int i = 1; true; i++) {
|
||||
String entry = Security.getProperty("security.provider." + i);
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
entry = entry.trim();
|
||||
if (entry.length() == 0) {
|
||||
System.err.println("invalid entry for " +
|
||||
"security.provider." + i);
|
||||
break;
|
||||
}
|
||||
int k = entry.indexOf(' ');
|
||||
ProviderConfig config;
|
||||
if (k == -1) {
|
||||
config = new ProviderConfig(entry);
|
||||
} else {
|
||||
String className = entry.substring(0, k);
|
||||
String argument = entry.substring(k + 1).trim();
|
||||
config = new ProviderConfig(className, argument);
|
||||
}
|
||||
|
||||
// Get rid of duplicate providers.
|
||||
if (configList.contains(config) == false) {
|
||||
configList.add(config);
|
||||
}
|
||||
}
|
||||
configs = configList.toArray(PC0);
|
||||
if (debug != null) {
|
||||
debug.println("provider configuration: " + configList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a special ProviderList for JAR verification. It consists
|
||||
* of the providers specified via jarClassNames, which must be on the
|
||||
* bootclasspath and cannot be in signed JAR files. This is to avoid
|
||||
* possible recursion and deadlock during verification.
|
||||
*/
|
||||
ProviderList getJarList(String[] jarClassNames) {
|
||||
List<ProviderConfig> newConfigs = new ArrayList<>();
|
||||
for (String className : jarClassNames) {
|
||||
ProviderConfig newConfig = new ProviderConfig(className);
|
||||
for (ProviderConfig config : configs) {
|
||||
// if the equivalent object is present in this provider list,
|
||||
// use the old object rather than the new object.
|
||||
// this ensures that when the provider is loaded in the
|
||||
// new thread local list, it will also become available
|
||||
// in this provider list
|
||||
if (config.equals(newConfig)) {
|
||||
newConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newConfigs.add(newConfig);
|
||||
}
|
||||
ProviderConfig[] configArray = newConfigs.toArray(PC0);
|
||||
return new ProviderList(configArray, false);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return configs.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Provider at the specified index. Returns EMPTY_PROVIDER
|
||||
* if the provider could not be loaded at this time.
|
||||
*/
|
||||
Provider getProvider(int index) {
|
||||
Provider p = configs[index].getProvider();
|
||||
return (p != null) ? p : EMPTY_PROVIDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unmodifiable List of all Providers in this List. The
|
||||
* individual Providers are loaded on demand. Elements that could not
|
||||
* be initialized are replaced with EMPTY_PROVIDER.
|
||||
*/
|
||||
public List<Provider> providers() {
|
||||
return userList;
|
||||
}
|
||||
|
||||
private ProviderConfig getProviderConfig(String name) {
|
||||
int index = getIndex(name);
|
||||
return (index != -1) ? configs[index] : null;
|
||||
}
|
||||
|
||||
// return the Provider with the specified name or null
|
||||
public Provider getProvider(String name) {
|
||||
ProviderConfig config = getProviderConfig(name);
|
||||
return (config == null) ? null : config.getProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index at which the provider with the specified name is
|
||||
* installed or -1 if it is not present in this ProviderList.
|
||||
*/
|
||||
public int getIndex(String name) {
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
Provider p = getProvider(i);
|
||||
if (p.getName().equals(name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// attempt to load all Providers not already loaded
|
||||
private int loadAll() {
|
||||
if (allLoaded) {
|
||||
return configs.length;
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Loading all providers");
|
||||
new Exception("Debug Info. Call trace:").printStackTrace();
|
||||
}
|
||||
int n = 0;
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
Provider p = configs[i].getProvider();
|
||||
if (p != null) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n == configs.length) {
|
||||
allLoaded = true;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load all Providers and return the ProviderList. If one or
|
||||
* more Providers could not be loaded, a new ProviderList with those
|
||||
* entries removed is returned. Otherwise, the method returns this.
|
||||
*/
|
||||
ProviderList removeInvalid() {
|
||||
int n = loadAll();
|
||||
if (n == configs.length) {
|
||||
return this;
|
||||
}
|
||||
ProviderConfig[] newConfigs = new ProviderConfig[n];
|
||||
for (int i = 0, j = 0; i < configs.length; i++) {
|
||||
ProviderConfig config = configs[i];
|
||||
if (config.isLoaded()) {
|
||||
newConfigs[j++] = config;
|
||||
}
|
||||
}
|
||||
return new ProviderList(newConfigs, true);
|
||||
}
|
||||
|
||||
// return the providers as an array
|
||||
public Provider[] toArray() {
|
||||
return providers().toArray(P0);
|
||||
}
|
||||
|
||||
// return a String representation of this ProviderList
|
||||
public String toString() {
|
||||
return Arrays.asList(configs).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Service describing an implementation of the specified
|
||||
* algorithm from the Provider with the highest precedence that
|
||||
* supports that algorithm. Return null if no Provider supports this
|
||||
* algorithm.
|
||||
*/
|
||||
public Service getService(String type, String name) {
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
Provider p = getProvider(i);
|
||||
Service s = p.getService(type, name);
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a List containing all the Services describing implementations
|
||||
* of the specified algorithms in precedence order. If no implementation
|
||||
* exists, this method returns an empty List.
|
||||
*
|
||||
* The elements of this list are determined lazily on demand.
|
||||
*
|
||||
* The List returned is NOT thread safe.
|
||||
*/
|
||||
public List<Service> getServices(String type, String algorithm) {
|
||||
return new ServiceList(type, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method exists for compatibility with JCE only. It will be removed
|
||||
* once JCE has been changed to use the replacement method.
|
||||
* @deprecated use getServices(List<ServiceId>) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public List<Service> getServices(String type, List<String> algorithms) {
|
||||
List<ServiceId> ids = new ArrayList<>();
|
||||
for (String alg : algorithms) {
|
||||
ids.add(new ServiceId(type, alg));
|
||||
}
|
||||
return getServices(ids);
|
||||
}
|
||||
|
||||
public List<Service> getServices(List<ServiceId> ids) {
|
||||
return new ServiceList(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class for a List of Services. Custom List implementation in
|
||||
* order to delay Provider initialization and lookup.
|
||||
* Not thread safe.
|
||||
*/
|
||||
private final class ServiceList extends AbstractList<Service> {
|
||||
|
||||
// type and algorithm for simple lookup
|
||||
// avoid allocating/traversing the ServiceId list for these lookups
|
||||
private final String type;
|
||||
private final String algorithm;
|
||||
|
||||
// list of ids for parallel lookup
|
||||
// if ids is non-null, type and algorithm are null
|
||||
private final List<ServiceId> ids;
|
||||
|
||||
// first service we have found
|
||||
// it is stored in a separate variable so that we can avoid
|
||||
// allocating the services list if we do not need the second service.
|
||||
// this is the case if we don't failover (failovers are typically rare)
|
||||
private Service firstService;
|
||||
|
||||
// list of the services we have found so far
|
||||
private List<Service> services;
|
||||
|
||||
// index into config[] of the next provider we need to query
|
||||
private int providerIndex;
|
||||
|
||||
ServiceList(String type, String algorithm) {
|
||||
this.type = type;
|
||||
this.algorithm = algorithm;
|
||||
this.ids = null;
|
||||
}
|
||||
|
||||
ServiceList(List<ServiceId> ids) {
|
||||
this.type = null;
|
||||
this.algorithm = null;
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
private void addService(Service s) {
|
||||
if (firstService == null) {
|
||||
firstService = s;
|
||||
} else {
|
||||
if (services == null) {
|
||||
services = new ArrayList<Service>(4);
|
||||
services.add(firstService);
|
||||
}
|
||||
services.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
private Service tryGet(int index) {
|
||||
while (true) {
|
||||
if ((index == 0) && (firstService != null)) {
|
||||
return firstService;
|
||||
} else if ((services != null) && (services.size() > index)) {
|
||||
return services.get(index);
|
||||
}
|
||||
if (providerIndex >= configs.length) {
|
||||
return null;
|
||||
}
|
||||
// check all algorithms in this provider before moving on
|
||||
Provider p = getProvider(providerIndex++);
|
||||
if (type != null) {
|
||||
// simple lookup
|
||||
Service s = p.getService(type, algorithm);
|
||||
if (s != null) {
|
||||
addService(s);
|
||||
}
|
||||
} else {
|
||||
// parallel lookup
|
||||
for (ServiceId id : ids) {
|
||||
Service s = p.getService(id.type, id.algorithm);
|
||||
if (s != null) {
|
||||
addService(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Service get(int index) {
|
||||
Service s = tryGet(index);
|
||||
if (s == null) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
int n;
|
||||
if (services != null) {
|
||||
n = services.size();
|
||||
} else {
|
||||
n = (firstService != null) ? 1 : 0;
|
||||
}
|
||||
while (tryGet(n) != null) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// override isEmpty() and iterator() to not call size()
|
||||
// this avoids loading + checking all Providers
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (tryGet(0) == null);
|
||||
}
|
||||
|
||||
public Iterator<Service> iterator() {
|
||||
return new Iterator<Service>() {
|
||||
int index;
|
||||
|
||||
public boolean hasNext() {
|
||||
return tryGet(index) != null;
|
||||
}
|
||||
|
||||
public Service next() {
|
||||
Service s = tryGet(index);
|
||||
if (s == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
index++;
|
||||
return s;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
248
jdkSrc/jdk8/sun/security/jca/Providers.java
Normal file
248
jdkSrc/jdk8/sun/security/jca/Providers.java
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* Collection of methods to get and set provider list. Also includes
|
||||
* special code for the provider list during JAR verification.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public class Providers {
|
||||
|
||||
private static final ThreadLocal<ProviderList> threadLists =
|
||||
new InheritableThreadLocal<>();
|
||||
|
||||
// number of threads currently using thread-local provider lists
|
||||
// tracked to allow an optimization if == 0
|
||||
private static volatile int threadListsUsed;
|
||||
|
||||
// current system-wide provider list
|
||||
// Note volatile immutable object, so no synchronization needed.
|
||||
private static volatile ProviderList providerList;
|
||||
|
||||
static {
|
||||
// set providerList to empty list first in case initialization somehow
|
||||
// triggers a getInstance() call (although that should not happen)
|
||||
providerList = ProviderList.EMPTY;
|
||||
providerList = ProviderList.fromSecurityProperties();
|
||||
}
|
||||
|
||||
private Providers() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// we need special handling to resolve circularities when loading
|
||||
// signed JAR files during startup. The code below is part of that.
|
||||
|
||||
// Basically, before we load data from a signed JAR file, we parse
|
||||
// the PKCS#7 file and verify the signature. We need a
|
||||
// CertificateFactory, Signatures, etc. to do that. We have to make
|
||||
// sure that we do not try to load the implementation from the JAR
|
||||
// file we are just verifying.
|
||||
//
|
||||
// To avoid that, we use different provider settings during JAR
|
||||
// verification. However, we do not want those provider settings to
|
||||
// interfere with other parts of the system. Therefore, we make them local
|
||||
// to the Thread executing the JAR verification code.
|
||||
//
|
||||
// The code here is used by sun.security.util.SignatureFileVerifier.
|
||||
// See there for details.
|
||||
|
||||
private static final String BACKUP_PROVIDER_CLASSNAME =
|
||||
"sun.security.provider.VerificationProvider";
|
||||
|
||||
// Hardcoded classnames of providers to use for JAR verification.
|
||||
// MUST NOT be on the bootclasspath and not in signed JAR files.
|
||||
private static final String[] jarVerificationProviders = {
|
||||
"sun.security.provider.Sun",
|
||||
"sun.security.rsa.SunRsaSign",
|
||||
// Note: SunEC *is* in a signed JAR file, but it's not signed
|
||||
// by EC itself. So it's still safe to be listed here.
|
||||
"sun.security.ec.SunEC",
|
||||
"com.sun.crypto.provider.SunJCE",
|
||||
BACKUP_PROVIDER_CLASSNAME,
|
||||
};
|
||||
|
||||
// Return to Sun provider or its backup.
|
||||
// This method should only be called by
|
||||
// sun.security.util.ManifestEntryVerifier and java.security.SecureRandom.
|
||||
public static Provider getSunProvider() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(jarVerificationProviders[0]);
|
||||
return (Provider)clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(BACKUP_PROVIDER_CLASSNAME);
|
||||
return (Provider)clazz.newInstance();
|
||||
} catch (Exception ee) {
|
||||
throw new RuntimeException("Sun provider not found", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start JAR verification. This sets a special provider list for
|
||||
* the current thread. You MUST save the return value from this
|
||||
* method and you MUST call stopJarVerification() with that object
|
||||
* once you are done.
|
||||
*/
|
||||
public static Object startJarVerification() {
|
||||
ProviderList currentList = getProviderList();
|
||||
ProviderList jarList = currentList.getJarList(jarVerificationProviders);
|
||||
// return the old thread-local provider list, usually null
|
||||
return beginThreadProviderList(jarList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop JAR verification. Call once you have completed JAR verification.
|
||||
*/
|
||||
public static void stopJarVerification(Object obj) {
|
||||
// restore old thread-local provider list
|
||||
endThreadProviderList((ProviderList)obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current ProviderList. If the thread-local list is set,
|
||||
* it is returned. Otherwise, the system wide list is returned.
|
||||
*/
|
||||
public static ProviderList getProviderList() {
|
||||
ProviderList list = getThreadProviderList();
|
||||
if (list == null) {
|
||||
list = getSystemProviderList();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current ProviderList. Affects the thread-local list if set,
|
||||
* otherwise the system wide list.
|
||||
*/
|
||||
public static void setProviderList(ProviderList newList) {
|
||||
if (getThreadProviderList() == null) {
|
||||
setSystemProviderList(newList);
|
||||
} else {
|
||||
changeThreadProviderList(newList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full provider list with invalid providers (those that
|
||||
* could not be loaded) removed. This is the list we need to
|
||||
* present to applications.
|
||||
*/
|
||||
public static ProviderList getFullProviderList() {
|
||||
ProviderList list;
|
||||
synchronized (Providers.class) {
|
||||
list = getThreadProviderList();
|
||||
if (list != null) {
|
||||
ProviderList newList = list.removeInvalid();
|
||||
if (newList != list) {
|
||||
changeThreadProviderList(newList);
|
||||
list = newList;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
list = getSystemProviderList();
|
||||
ProviderList newList = list.removeInvalid();
|
||||
if (newList != list) {
|
||||
setSystemProviderList(newList);
|
||||
list = newList;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static ProviderList getSystemProviderList() {
|
||||
return providerList;
|
||||
}
|
||||
|
||||
private static void setSystemProviderList(ProviderList list) {
|
||||
providerList = list;
|
||||
}
|
||||
|
||||
public static ProviderList getThreadProviderList() {
|
||||
// avoid accessing the threadlocal if none are currently in use
|
||||
// (first use of ThreadLocal.get() for a Thread allocates a Map)
|
||||
if (threadListsUsed == 0) {
|
||||
return null;
|
||||
}
|
||||
return threadLists.get();
|
||||
}
|
||||
|
||||
// Change the thread local provider list. Use only if the current thread
|
||||
// is already using a thread local list and you want to change it in place.
|
||||
// In other cases, use the begin/endThreadProviderList() methods.
|
||||
private static void changeThreadProviderList(ProviderList list) {
|
||||
threadLists.set(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods to manipulate the thread local provider list. It is for use by
|
||||
* JAR verification (see above) and the SunJSSE FIPS mode only.
|
||||
*
|
||||
* It should be used as follows:
|
||||
*
|
||||
* ProviderList list = ...;
|
||||
* ProviderList oldList = Providers.beginThreadProviderList(list);
|
||||
* try {
|
||||
* // code that needs thread local provider list
|
||||
* } finally {
|
||||
* Providers.endThreadProviderList(oldList);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
public static synchronized ProviderList beginThreadProviderList(ProviderList list) {
|
||||
if (ProviderList.debug != null) {
|
||||
ProviderList.debug.println("ThreadLocal providers: " + list);
|
||||
}
|
||||
ProviderList oldList = threadLists.get();
|
||||
threadListsUsed++;
|
||||
threadLists.set(list);
|
||||
return oldList;
|
||||
}
|
||||
|
||||
public static synchronized void endThreadProviderList(ProviderList list) {
|
||||
if (list == null) {
|
||||
if (ProviderList.debug != null) {
|
||||
ProviderList.debug.println("Disabling ThreadLocal providers");
|
||||
}
|
||||
threadLists.remove();
|
||||
} else {
|
||||
if (ProviderList.debug != null) {
|
||||
ProviderList.debug.println
|
||||
("Restoring previous ThreadLocal providers: " + list);
|
||||
}
|
||||
threadLists.set(list);
|
||||
}
|
||||
threadListsUsed--;
|
||||
}
|
||||
|
||||
}
|
||||
45
jdkSrc/jdk8/sun/security/jca/ServiceId.java
Normal file
45
jdkSrc/jdk8/sun/security/jca/ServiceId.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jca;
|
||||
|
||||
/**
|
||||
* Simple class encapsulating a service type and algorithm for lookup.
|
||||
* Put in a separate file rather than nested to allow import via ...jca.*.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class ServiceId {
|
||||
|
||||
public final String type;
|
||||
public final String algorithm;
|
||||
|
||||
public ServiceId(String type, String algorithm) {
|
||||
this.type = type;
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
}
|
||||
49
jdkSrc/jdk8/sun/security/jgss/GSSCaller.java
Normal file
49
jdkSrc/jdk8/sun/security/jgss/GSSCaller.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
/**
|
||||
* Denotes what client is calling the JGSS-API. The object can be sent deep
|
||||
* into the mechanism level so that special actions can be performed for
|
||||
* different callers.
|
||||
*/
|
||||
public class GSSCaller {
|
||||
public static final GSSCaller CALLER_UNKNOWN = new GSSCaller("UNKNOWN");
|
||||
public static final GSSCaller CALLER_INITIATE = new GSSCaller("INITIATE");
|
||||
public static final GSSCaller CALLER_ACCEPT = new GSSCaller("ACCEPT");
|
||||
public static final GSSCaller CALLER_SSL_CLIENT = new GSSCaller("SSL_CLIENT");
|
||||
public static final GSSCaller CALLER_SSL_SERVER = new GSSCaller("SSL_SERVER");
|
||||
|
||||
private String name;
|
||||
GSSCaller(String s) {
|
||||
name = s;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GSSCaller{" + name + '}';
|
||||
}
|
||||
}
|
||||
|
||||
661
jdkSrc/jdk8/sun/security/jgss/GSSContextImpl.java
Normal file
661
jdkSrc/jdk8/sun/security/jgss/GSSContextImpl.java
Normal file
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import com.sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This class represents the JGSS security context and its associated
|
||||
* operations. JGSS security contexts are established between
|
||||
* peers using locally established credentials. Multiple contexts
|
||||
* may exist simultaneously between a pair of peers, using the same
|
||||
* or different set of credentials. The JGSS is independent of
|
||||
* the underlying transport protocols and depends on its callers to
|
||||
* transport the tokens between peers.
|
||||
* <p>
|
||||
* The context object can be thought of as having 3 implicit states:
|
||||
* before it is established, during its context establishment, and
|
||||
* after a fully established context exists.
|
||||
* <p>
|
||||
* Before the context establishment phase is initiated, the context
|
||||
* initiator may request specific characteristics desired of the
|
||||
* established context. These can be set using the set methods. After the
|
||||
* context is established, the caller can check the actual characteristic
|
||||
* and services offered by the context using the query methods.
|
||||
* <p>
|
||||
* The context establishment phase begins with the first call to the
|
||||
* initSecContext method by the context initiator. During this phase the
|
||||
* initSecContext and acceptSecContext methods will produce GSS-API
|
||||
* authentication tokens which the calling application needs to send to its
|
||||
* peer. The initSecContext and acceptSecContext methods may
|
||||
* return a CONTINUE_NEEDED code which indicates that a token is needed
|
||||
* from its peer in order to continue the context establishment phase. A
|
||||
* return code of COMPLETE signals that the local end of the context is
|
||||
* established. This may still require that a token be sent to the peer,
|
||||
* depending if one is produced by GSS-API. The isEstablished method can
|
||||
* also be used to determine if the local end of the context has been
|
||||
* fully established. During the context establishment phase, the
|
||||
* isProtReady method may be called to determine if the context can be
|
||||
* used for the per-message operations. This allows implementation to
|
||||
* use per-message operations on contexts which aren't fully established.
|
||||
* <p>
|
||||
* After the context has been established or the isProtReady method
|
||||
* returns "true", the query routines can be invoked to determine the actual
|
||||
* characteristics and services of the established context. The
|
||||
* application can also start using the per-message methods of wrap and
|
||||
* getMIC to obtain cryptographic operations on application supplied data.
|
||||
* <p>
|
||||
* When the context is no longer needed, the application should call
|
||||
* dispose to release any system resources the context may be using.
|
||||
* <DL><DT><B>RFC 2078</b>
|
||||
* <DD>This class corresponds to the context level calls together with
|
||||
* the per message calls of RFC 2078. The gss_init_sec_context and
|
||||
* gss_accept_sec_context calls have been made simpler by only taking
|
||||
* required parameters. The context can have its properties set before
|
||||
* the first call to initSecContext. The supplementary status codes for the
|
||||
* per-message operations are returned in an instance of the MessageProp
|
||||
* class, which is used as an argument in these calls.</dl>
|
||||
*/
|
||||
class GSSContextImpl implements ExtendedGSSContext {
|
||||
|
||||
private final GSSManagerImpl gssManager;
|
||||
private final boolean initiator;
|
||||
|
||||
// private flags for the context state
|
||||
private static final int PRE_INIT = 1;
|
||||
private static final int IN_PROGRESS = 2;
|
||||
private static final int READY = 3;
|
||||
private static final int DELETED = 4;
|
||||
|
||||
// instance variables
|
||||
private int currentState = PRE_INIT;
|
||||
|
||||
private GSSContextSpi mechCtxt = null;
|
||||
private Oid mechOid = null;
|
||||
private ObjectIdentifier objId = null;
|
||||
|
||||
private GSSCredentialImpl myCred = null;
|
||||
|
||||
private GSSNameImpl srcName = null;
|
||||
private GSSNameImpl targName = null;
|
||||
|
||||
private int reqLifetime = INDEFINITE_LIFETIME;
|
||||
private ChannelBinding channelBindings = null;
|
||||
|
||||
private boolean reqConfState = true;
|
||||
private boolean reqIntegState = true;
|
||||
private boolean reqMutualAuthState = true;
|
||||
private boolean reqReplayDetState = true;
|
||||
private boolean reqSequenceDetState = true;
|
||||
private boolean reqCredDelegState = false;
|
||||
private boolean reqAnonState = false;
|
||||
private boolean reqDelegPolicyState = false;
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImp on the context initiator's side.
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, GSSName peer, Oid mech,
|
||||
GSSCredential myCred, int lifetime)
|
||||
throws GSSException {
|
||||
if ((peer == null) || !(peer instanceof GSSNameImpl)) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
this.gssManager = gssManager;
|
||||
this.myCred = (GSSCredentialImpl) myCred; // XXX Check first
|
||||
reqLifetime = lifetime;
|
||||
targName = (GSSNameImpl)peer;
|
||||
this.mechOid = mech;
|
||||
initiator = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImpl on the context acceptor's side.
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, GSSCredential myCred)
|
||||
throws GSSException {
|
||||
this.gssManager = gssManager;
|
||||
this.myCred = (GSSCredentialImpl) myCred; // XXX Check first
|
||||
initiator = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImpl out of a previously exported
|
||||
* GSSContext.
|
||||
*
|
||||
* @see #isTransferable
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, byte[] interProcessToken)
|
||||
throws GSSException {
|
||||
this.gssManager = gssManager;
|
||||
mechCtxt = gssManager.getMechanismContext(interProcessToken);
|
||||
initiator = mechCtxt.isInitiator();
|
||||
this.mechOid = mechCtxt.getMech();
|
||||
}
|
||||
|
||||
public byte[] initSecContext(byte inputBuf[], int offset, int len)
|
||||
throws GSSException {
|
||||
/*
|
||||
* Size of ByteArrayOutputStream will double each time that extra
|
||||
* bytes are to be written. Usually, without delegation, a GSS
|
||||
* initial token containing the Kerberos AP-REQ is between 400 and
|
||||
* 600 bytes.
|
||||
*/
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(600);
|
||||
ByteArrayInputStream bin =
|
||||
new ByteArrayInputStream(inputBuf, offset, len);
|
||||
int size = initSecContext(bin, bos);
|
||||
return (size == 0? null : bos.toByteArray());
|
||||
}
|
||||
|
||||
public int initSecContext(InputStream inStream,
|
||||
OutputStream outStream) throws GSSException {
|
||||
|
||||
if (mechCtxt != null && currentState != IN_PROGRESS) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Illegal call to initSecContext");
|
||||
}
|
||||
|
||||
GSSHeader gssHeader = null;
|
||||
int inTokenLen = -1;
|
||||
GSSCredentialSpi credElement = null;
|
||||
boolean firstToken = false;
|
||||
|
||||
try {
|
||||
if (mechCtxt == null) {
|
||||
if (myCred != null) {
|
||||
try {
|
||||
credElement = myCred.getElement(mechOid, true);
|
||||
} catch (GSSException ge) {
|
||||
if (GSSUtil.isSpNegoMech(mechOid) &&
|
||||
ge.getMajor() == GSSException.NO_CRED) {
|
||||
credElement = myCred.getElement
|
||||
(myCred.getMechs()[0], true);
|
||||
} else {
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
}
|
||||
GSSNameSpi nameElement = targName.getElement(mechOid);
|
||||
mechCtxt = gssManager.getMechanismContext(nameElement,
|
||||
credElement,
|
||||
reqLifetime,
|
||||
mechOid);
|
||||
mechCtxt.requestConf(reqConfState);
|
||||
mechCtxt.requestInteg(reqIntegState);
|
||||
mechCtxt.requestCredDeleg(reqCredDelegState);
|
||||
mechCtxt.requestMutualAuth(reqMutualAuthState);
|
||||
mechCtxt.requestReplayDet(reqReplayDetState);
|
||||
mechCtxt.requestSequenceDet(reqSequenceDetState);
|
||||
mechCtxt.requestAnonymity(reqAnonState);
|
||||
mechCtxt.setChannelBinding(channelBindings);
|
||||
mechCtxt.requestDelegPolicy(reqDelegPolicyState);
|
||||
|
||||
objId = new ObjectIdentifier(mechOid.toString());
|
||||
|
||||
currentState = IN_PROGRESS;
|
||||
firstToken = true;
|
||||
} else {
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
GSSUtil.isSpNegoMech(mechOid)) {
|
||||
// do not parse GSS header for native provider or SPNEGO
|
||||
// mech
|
||||
} else {
|
||||
// parse GSS header
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
if (!gssHeader.getOid().equals((Object) objId))
|
||||
throw new GSSExceptionImpl
|
||||
(GSSException.DEFECTIVE_TOKEN,
|
||||
"Mechanism not equal to " +
|
||||
mechOid.toString() +
|
||||
" in initSecContext token");
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] obuf = mechCtxt.initSecContext(inStream, inTokenLen);
|
||||
|
||||
int retVal = 0;
|
||||
|
||||
if (obuf != null) {
|
||||
retVal = obuf.length;
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(!firstToken && GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not add GSS header for native provider or SPNEGO
|
||||
// except for the first SPNEGO token
|
||||
} else {
|
||||
// add GSS header
|
||||
gssHeader = new GSSHeader(objId, obuf.length);
|
||||
retVal += gssHeader.encode(outStream);
|
||||
}
|
||||
outStream.write(obuf);
|
||||
}
|
||||
|
||||
if (mechCtxt.isEstablished())
|
||||
currentState = READY;
|
||||
|
||||
return retVal;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] acceptSecContext(byte inTok[], int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
/*
|
||||
* Usually initial GSS token containing a Kerberos AP-REP is less
|
||||
* than 100 bytes.
|
||||
*/
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(100);
|
||||
acceptSecContext(new ByteArrayInputStream(inTok, offset, len),
|
||||
bos);
|
||||
byte[] out = bos.toByteArray();
|
||||
return (out.length == 0) ? null : out;
|
||||
}
|
||||
|
||||
public void acceptSecContext(InputStream inStream,
|
||||
OutputStream outStream) throws GSSException {
|
||||
|
||||
if (mechCtxt != null && currentState != IN_PROGRESS) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Illegal call to acceptSecContext");
|
||||
}
|
||||
|
||||
GSSHeader gssHeader = null;
|
||||
int inTokenLen = -1;
|
||||
GSSCredentialSpi credElement = null;
|
||||
|
||||
try {
|
||||
if (mechCtxt == null) {
|
||||
// mechOid will be null for an acceptor's context
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
|
||||
/*
|
||||
* Convert ObjectIdentifier to Oid
|
||||
*/
|
||||
objId = gssHeader.getOid();
|
||||
mechOid = new Oid(objId.toString());
|
||||
// System.out.println("Entered GSSContextImpl.acceptSecContext"
|
||||
// + " with mechanism = " + mechOid);
|
||||
if (myCred != null) {
|
||||
credElement = myCred.getElement(mechOid, false);
|
||||
}
|
||||
|
||||
mechCtxt = gssManager.getMechanismContext(credElement,
|
||||
mechOid);
|
||||
mechCtxt.setChannelBinding(channelBindings);
|
||||
|
||||
currentState = IN_PROGRESS;
|
||||
} else {
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not parse GSS header for native provider and SPNEGO
|
||||
} else {
|
||||
// parse GSS Header
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
if (!gssHeader.getOid().equals((Object) objId))
|
||||
throw new GSSExceptionImpl
|
||||
(GSSException.DEFECTIVE_TOKEN,
|
||||
"Mechanism not equal to " +
|
||||
mechOid.toString() +
|
||||
" in acceptSecContext token");
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] obuf = mechCtxt.acceptSecContext(inStream, inTokenLen);
|
||||
|
||||
if (obuf != null) {
|
||||
int retVal = obuf.length;
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not add GSS header for native provider and SPNEGO
|
||||
} else {
|
||||
// add GSS header
|
||||
gssHeader = new GSSHeader(objId, obuf.length);
|
||||
retVal += gssHeader.encode(outStream);
|
||||
}
|
||||
outStream.write(obuf);
|
||||
}
|
||||
|
||||
if (mechCtxt.isEstablished()) {
|
||||
currentState = READY;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEstablished() {
|
||||
if (mechCtxt == null)
|
||||
return false;
|
||||
else
|
||||
return (currentState == READY);
|
||||
}
|
||||
|
||||
public int getWrapSizeLimit(int qop, boolean confReq,
|
||||
int maxTokenSize) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getWrapSizeLimit(qop, confReq, maxTokenSize);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] wrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.wrap(inBuf, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void wrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.wrap(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte [] unwrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.unwrap(inBuf, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void unwrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.unwrap(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] getMIC(byte []inMsg, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getMIC(inMsg, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void getMIC(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.getMIC(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
|
||||
byte[] inMsg, int msgOffset, int msgLen,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.verifyMIC(inTok, tokOffset, tokLen,
|
||||
inMsg, msgOffset, msgLen, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void verifyMIC(InputStream tokStream, InputStream msgStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.verifyMIC(tokStream, msgStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
// Defaults to null to match old behavior
|
||||
byte[] result = null;
|
||||
// Only allow context export from native provider since JGSS
|
||||
// still has not defined its own interprocess token format
|
||||
if (mechCtxt.isTransferable() &&
|
||||
mechCtxt.getProvider().getName().equals("SunNativeGSS")) {
|
||||
result = mechCtxt.export();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void requestMutualAuth(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqMutualAuthState = state;
|
||||
}
|
||||
|
||||
public void requestReplayDet(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqReplayDetState = state;
|
||||
}
|
||||
|
||||
public void requestSequenceDet(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqSequenceDetState = state;
|
||||
}
|
||||
|
||||
public void requestCredDeleg(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqCredDelegState = state;
|
||||
}
|
||||
|
||||
public void requestAnonymity(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqAnonState = state;
|
||||
}
|
||||
|
||||
public void requestConf(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqConfState = state;
|
||||
}
|
||||
|
||||
public void requestInteg(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqIntegState = state;
|
||||
}
|
||||
|
||||
public void requestLifetime(int lifetime) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqLifetime = lifetime;
|
||||
}
|
||||
|
||||
public void setChannelBinding(ChannelBinding channelBindings)
|
||||
throws GSSException {
|
||||
|
||||
if (mechCtxt == null)
|
||||
this.channelBindings = channelBindings;
|
||||
|
||||
}
|
||||
|
||||
public boolean getCredDelegState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getCredDelegState();
|
||||
else
|
||||
return reqCredDelegState;
|
||||
}
|
||||
|
||||
public boolean getMutualAuthState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getMutualAuthState();
|
||||
else
|
||||
return reqMutualAuthState;
|
||||
}
|
||||
|
||||
public boolean getReplayDetState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getReplayDetState();
|
||||
else
|
||||
return reqReplayDetState;
|
||||
}
|
||||
|
||||
public boolean getSequenceDetState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getSequenceDetState();
|
||||
else
|
||||
return reqSequenceDetState;
|
||||
}
|
||||
|
||||
public boolean getAnonymityState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getAnonymityState();
|
||||
else
|
||||
return reqAnonState;
|
||||
}
|
||||
|
||||
public boolean isTransferable() throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.isTransferable();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isProtReady() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.isProtReady();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getConfState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getConfState();
|
||||
else
|
||||
return reqConfState;
|
||||
}
|
||||
|
||||
public boolean getIntegState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getIntegState();
|
||||
else
|
||||
return reqIntegState;
|
||||
}
|
||||
|
||||
public int getLifetime() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getLifetime();
|
||||
else
|
||||
return reqLifetime;
|
||||
}
|
||||
|
||||
public GSSName getSrcName() throws GSSException {
|
||||
if (srcName == null) {
|
||||
srcName = GSSNameImpl.wrapElement
|
||||
(gssManager, mechCtxt.getSrcName());
|
||||
}
|
||||
return srcName;
|
||||
}
|
||||
|
||||
public GSSName getTargName() throws GSSException {
|
||||
if (targName == null) {
|
||||
targName = GSSNameImpl.wrapElement
|
||||
(gssManager, mechCtxt.getTargName());
|
||||
}
|
||||
return targName;
|
||||
}
|
||||
|
||||
public Oid getMech() throws GSSException {
|
||||
if (mechCtxt != null) {
|
||||
return mechCtxt.getMech();
|
||||
}
|
||||
return mechOid;
|
||||
}
|
||||
|
||||
public GSSCredential getDelegCred() throws GSSException {
|
||||
|
||||
if (mechCtxt == null)
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
GSSCredentialSpi delCredElement = mechCtxt.getDelegCred();
|
||||
return (delCredElement == null ?
|
||||
null : new GSSCredentialImpl(gssManager, delCredElement));
|
||||
}
|
||||
|
||||
public boolean isInitiator() throws GSSException {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
currentState = DELETED;
|
||||
if (mechCtxt != null) {
|
||||
mechCtxt.dispose();
|
||||
mechCtxt = null;
|
||||
}
|
||||
myCred = null;
|
||||
srcName = null;
|
||||
targName = null;
|
||||
}
|
||||
|
||||
// ExtendedGSSContext methods:
|
||||
|
||||
@Override
|
||||
public Object inquireSecContext(InquireType type) throws GSSException {
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkPermission(new InquireSecContextPermission(type.toString()));
|
||||
}
|
||||
if (mechCtxt == null) {
|
||||
throw new GSSException(GSSException.NO_CONTEXT);
|
||||
}
|
||||
return mechCtxt.inquireSecContext(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDelegPolicy(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqDelegPolicyState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDelegPolicyState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getDelegPolicyState();
|
||||
else
|
||||
return reqDelegPolicyState;
|
||||
}
|
||||
}
|
||||
690
jdkSrc/jdk8/sun/security/jgss/GSSCredentialImpl.java
Normal file
690
jdkSrc/jdk8/sun/security/jgss/GSSCredentialImpl.java
Normal file
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.util.*;
|
||||
import com.sun.security.jgss.*;
|
||||
import sun.security.jgss.spnego.SpNegoCredElement;
|
||||
|
||||
public class GSSCredentialImpl implements ExtendedGSSCredential {
|
||||
|
||||
private GSSManagerImpl gssManager = null;
|
||||
private boolean destroyed = false;
|
||||
|
||||
/*
|
||||
* We store all elements in a hashtable, using <oid, usage> as the
|
||||
* key. This makes it easy to locate the specific kind of credential we
|
||||
* need. The implementation needs to be optimized for the case where
|
||||
* there is just one element (tempCred).
|
||||
*/
|
||||
private Hashtable<SearchKey, GSSCredentialSpi> hashtable = null;
|
||||
|
||||
// XXX Optimization for single mech usage
|
||||
private GSSCredentialSpi tempCred = null;
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, int usage)
|
||||
throws GSSException {
|
||||
this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,
|
||||
(Oid[]) null, usage);
|
||||
}
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
|
||||
int lifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
init(gssManager);
|
||||
add(name, lifetime, lifetime, mech, usage);
|
||||
}
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
|
||||
int lifetime, Oid mechs[], int usage)
|
||||
throws GSSException {
|
||||
init(gssManager);
|
||||
boolean defaultList = false;
|
||||
if (mechs == null) {
|
||||
mechs = gssManager.getMechs();
|
||||
defaultList = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
try {
|
||||
add(name, lifetime, lifetime, mechs[i], usage);
|
||||
} catch (GSSException e) {
|
||||
if (defaultList) {
|
||||
// Try the next mechanism
|
||||
GSSUtil.debug("Ignore " + e + " while acquring cred for "
|
||||
+ mechs[i]);
|
||||
//e.printStackTrace();
|
||||
} else throw e; // else try the next mechanism
|
||||
}
|
||||
}
|
||||
if ((hashtable.size() == 0) || (usage != getUsage()))
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
|
||||
// Wrap a mech cred into a GSS cred
|
||||
public GSSCredentialImpl(GSSManagerImpl gssManager,
|
||||
GSSCredentialSpi mechElement) throws GSSException {
|
||||
|
||||
init(gssManager);
|
||||
int usage = GSSCredential.ACCEPT_ONLY;
|
||||
if (mechElement.isInitiatorCredential()) {
|
||||
if (mechElement.isAcceptorCredential()) {
|
||||
usage = GSSCredential.INITIATE_AND_ACCEPT;
|
||||
} else {
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
}
|
||||
}
|
||||
SearchKey key = new SearchKey(mechElement.getMechanism(),
|
||||
usage);
|
||||
tempCred = mechElement;
|
||||
hashtable.put(key, tempCred);
|
||||
// More mechs that can use this cred, say, SPNEGO
|
||||
if (!GSSUtil.isSpNegoMech(mechElement.getMechanism())) {
|
||||
key = new SearchKey(GSSUtil.GSS_SPNEGO_MECH_OID, usage);
|
||||
hashtable.put(key, new SpNegoCredElement(mechElement));
|
||||
}
|
||||
}
|
||||
|
||||
void init(GSSManagerImpl gssManager) {
|
||||
this.gssManager = gssManager;
|
||||
hashtable = new Hashtable<SearchKey, GSSCredentialSpi>(
|
||||
gssManager.getMechs().length);
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
if (!destroyed) {
|
||||
GSSCredentialSpi element;
|
||||
Enumeration<GSSCredentialSpi> values = hashtable.elements();
|
||||
while (values.hasMoreElements()) {
|
||||
element = values.nextElement();
|
||||
element.dispose();
|
||||
}
|
||||
destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public GSSCredential impersonate(GSSName name) throws GSSException {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
Oid mech = tempCred.getMechanism();
|
||||
GSSNameSpi nameElement = (name == null ? null :
|
||||
((GSSNameImpl)name).getElement(mech));
|
||||
GSSCredentialSpi cred = tempCred.impersonate(nameElement);
|
||||
return (cred == null ?
|
||||
null : new GSSCredentialImpl(gssManager, cred));
|
||||
}
|
||||
|
||||
public GSSName getName() throws GSSException {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
return GSSNameImpl.wrapElement(gssManager, tempCred.getName());
|
||||
}
|
||||
|
||||
public GSSName getName(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey key = null;
|
||||
GSSCredentialSpi element = null;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return GSSNameImpl.wrapElement(gssManager, element.getName());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remaining lifetime of this credential. The remaining
|
||||
* lifetime is defined as the minimum lifetime, either for initiate or
|
||||
* for accept, across all elements contained in it. Not terribly
|
||||
* useful, but required by GSS-API.
|
||||
*/
|
||||
public int getRemainingLifetime() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey tempKey;
|
||||
GSSCredentialSpi tempCred;
|
||||
int tempLife = 0, tempInitLife = 0, tempAcceptLife = 0;
|
||||
int min = INDEFINITE_LIFETIME;
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
tempKey = e.nextElement();
|
||||
tempCred = hashtable.get(tempKey);
|
||||
if (tempKey.getUsage() == INITIATE_ONLY)
|
||||
tempLife = tempCred.getInitLifetime();
|
||||
else if (tempKey.getUsage() == ACCEPT_ONLY)
|
||||
tempLife = tempCred.getAcceptLifetime();
|
||||
else {
|
||||
tempInitLife = tempCred.getInitLifetime();
|
||||
tempAcceptLife = tempCred.getAcceptLifetime();
|
||||
tempLife = (tempInitLife < tempAcceptLife ?
|
||||
tempInitLife:
|
||||
tempAcceptLife);
|
||||
}
|
||||
if (min > tempLife)
|
||||
min = tempLife;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public int getRemainingInitLifetime(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean found = false;
|
||||
int max = 0;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getInitLifetime())
|
||||
max = element.getInitLifetime();
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getInitLifetime())
|
||||
max = element.getInitLifetime();
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
public int getRemainingAcceptLifetime(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean found = false;
|
||||
int max = 0;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getAcceptLifetime())
|
||||
max = element.getAcceptLifetime();
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getAcceptLifetime())
|
||||
max = element.getAcceptLifetime();
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the usage mode for this credential. Returns
|
||||
* INITIATE_AND_ACCEPT if any one element contained in it supports
|
||||
* INITIATE_AND_ACCEPT or if two different elements exist where one
|
||||
* support INITIATE_ONLY and the other supports ACCEPT_ONLY.
|
||||
*/
|
||||
public int getUsage() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey tempKey;
|
||||
boolean initiate = false;
|
||||
boolean accept = false;
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
tempKey = e.nextElement();
|
||||
if (tempKey.getUsage() == INITIATE_ONLY)
|
||||
initiate = true;
|
||||
else if (tempKey.getUsage() == ACCEPT_ONLY)
|
||||
accept = true;
|
||||
else
|
||||
return INITIATE_AND_ACCEPT;
|
||||
}
|
||||
if (initiate) {
|
||||
if (accept)
|
||||
return INITIATE_AND_ACCEPT;
|
||||
else
|
||||
return INITIATE_ONLY;
|
||||
} else
|
||||
return ACCEPT_ONLY;
|
||||
}
|
||||
|
||||
public int getUsage(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean initiate = false;
|
||||
boolean accept = false;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
initiate = true;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
accept = true;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
initiate = true;
|
||||
accept = true;
|
||||
}
|
||||
|
||||
if (initiate && accept)
|
||||
return GSSCredential.INITIATE_AND_ACCEPT;
|
||||
else if (initiate)
|
||||
return GSSCredential.INITIATE_ONLY;
|
||||
else if (accept)
|
||||
return GSSCredential.ACCEPT_ONLY;
|
||||
else {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
}
|
||||
|
||||
public Oid[] getMechs() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
Vector<Oid> result = new Vector<Oid>(hashtable.size());
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
SearchKey tempKey = e.nextElement();
|
||||
result.addElement(tempKey.getMech());
|
||||
}
|
||||
return result.toArray(new Oid[0]);
|
||||
}
|
||||
|
||||
public void add(GSSName name, int initLifetime, int acceptLifetime,
|
||||
Oid mech, int usage) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
SearchKey key = new SearchKey(mech, usage);
|
||||
if (hashtable.containsKey(key)) {
|
||||
throw new GSSExceptionImpl(GSSException.DUPLICATE_ELEMENT,
|
||||
"Duplicate element found: " +
|
||||
getElementStr(mech, usage));
|
||||
}
|
||||
|
||||
// XXX If not instance of GSSNameImpl then throw exception
|
||||
// Application mixing GSS implementations
|
||||
GSSNameSpi nameElement = (name == null ? null :
|
||||
((GSSNameImpl)name).getElement(mech));
|
||||
|
||||
tempCred = gssManager.getCredentialElement(nameElement,
|
||||
initLifetime,
|
||||
acceptLifetime,
|
||||
mech,
|
||||
usage);
|
||||
/*
|
||||
* Not all mechanisms support the concept of one credential element
|
||||
* that can be used for both initiating and accepting a context. In
|
||||
* the event that an application requests usage INITIATE_AND_ACCEPT
|
||||
* for a credential from such a mechanism, the GSS framework will
|
||||
* need to obtain two different credential elements from the
|
||||
* mechanism, one that will have usage INITIATE_ONLY and another
|
||||
* that will have usage ACCEPT_ONLY. The mechanism will help the
|
||||
* GSS-API realize this by returning a credential element with
|
||||
* usage INITIATE_ONLY or ACCEPT_ONLY prompting it to make another
|
||||
* call to getCredentialElement, this time with the other usage
|
||||
* mode.
|
||||
*/
|
||||
|
||||
if (tempCred != null) {
|
||||
if (usage == GSSCredential.INITIATE_AND_ACCEPT &&
|
||||
(!tempCred.isAcceptorCredential() ||
|
||||
!tempCred.isInitiatorCredential())) {
|
||||
|
||||
int currentUsage;
|
||||
int desiredUsage;
|
||||
|
||||
if (!tempCred.isInitiatorCredential()) {
|
||||
currentUsage = GSSCredential.ACCEPT_ONLY;
|
||||
desiredUsage = GSSCredential.INITIATE_ONLY;
|
||||
} else {
|
||||
currentUsage = GSSCredential.INITIATE_ONLY;
|
||||
desiredUsage = GSSCredential.ACCEPT_ONLY;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, currentUsage);
|
||||
hashtable.put(key, tempCred);
|
||||
|
||||
tempCred = gssManager.getCredentialElement(nameElement,
|
||||
initLifetime,
|
||||
acceptLifetime,
|
||||
mech,
|
||||
desiredUsage);
|
||||
|
||||
key = new SearchKey(mech, desiredUsage);
|
||||
hashtable.put(key, tempCred);
|
||||
} else {
|
||||
hashtable.put(key, tempCred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object another) {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
if (this == another) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(another instanceof GSSCredentialImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: The specification does not define the criteria to compare
|
||||
// credentials.
|
||||
/*
|
||||
* XXX
|
||||
* The RFC says: "Tests if this GSSCredential refers to the same
|
||||
* entity as the supplied object. The two credentials must be
|
||||
* acquired over the same mechanisms and must refer to the same
|
||||
* principal. Returns "true" if the two GSSCredentials refer to
|
||||
* the same entity; "false" otherwise."
|
||||
*
|
||||
* Well, when do two credentials refer to the same principal? Do
|
||||
* they need to have one GSSName in common for the different
|
||||
* GSSName's that the credential elements return? Or do all
|
||||
* GSSName's have to be in common when the names are exported with
|
||||
* their respective mechanisms for the credential elements?
|
||||
*/
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSCredential.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
// NOTE: The specification does not define the criteria to compare
|
||||
// credentials.
|
||||
/*
|
||||
* XXX
|
||||
* Decide on a criteria for equals first then do this.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified mechanism's credential-element.
|
||||
*
|
||||
* @param mechOid the oid for mechanism to retrieve
|
||||
* @param initiate boolean indicating if the function is
|
||||
* to throw exception or return null when element is not
|
||||
* found.
|
||||
* @return mechanism credential object
|
||||
* @exception GSSException of invalid mechanism
|
||||
*/
|
||||
public GSSCredentialSpi getElement(Oid mechOid, boolean initiate)
|
||||
throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey key;
|
||||
GSSCredentialSpi element;
|
||||
|
||||
if (mechOid == null) {
|
||||
/*
|
||||
* First see if the default mechanism satisfies the
|
||||
* desired usage.
|
||||
*/
|
||||
mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
key = new SearchKey(mechOid,
|
||||
initiate? INITIATE_ONLY : ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
if (element == null) {
|
||||
key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
if (element == null) {
|
||||
/*
|
||||
* Now just return any element that satisfies the
|
||||
* desired usage.
|
||||
*/
|
||||
Object[] elements = hashtable.entrySet().toArray();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
element = (GSSCredentialSpi)
|
||||
((Map.Entry)elements[i]).getValue();
|
||||
if (element.isInitiatorCredential() == initiate)
|
||||
break;
|
||||
} // for loop
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (initiate)
|
||||
key = new SearchKey(mechOid, INITIATE_ONLY);
|
||||
else
|
||||
key = new SearchKey(mechOid, ACCEPT_ONLY);
|
||||
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (element == null)
|
||||
throw new GSSExceptionImpl(GSSException.NO_CRED,
|
||||
"No credential found for: " +
|
||||
getElementStr(mechOid,
|
||||
initiate? INITIATE_ONLY : ACCEPT_ONLY));
|
||||
return element;
|
||||
}
|
||||
|
||||
Set<GSSCredentialSpi> getElements() {
|
||||
HashSet<GSSCredentialSpi> retVal =
|
||||
new HashSet<GSSCredentialSpi>(hashtable.size());
|
||||
Enumeration<GSSCredentialSpi> values = hashtable.elements();
|
||||
while (values.hasMoreElements()) {
|
||||
GSSCredentialSpi o = values.nextElement();
|
||||
retVal.add(o);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static String getElementStr(Oid mechOid, int usage) {
|
||||
String displayString = mechOid.toString();
|
||||
if (usage == GSSCredential.INITIATE_ONLY) {
|
||||
displayString =
|
||||
displayString.concat(" usage: Initiate");
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
displayString =
|
||||
displayString.concat(" usage: Accept");
|
||||
} else {
|
||||
displayString =
|
||||
displayString.concat(" usage: Initiate and Accept");
|
||||
}
|
||||
return displayString;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
StringBuffer buffer = new StringBuffer("[GSSCredential: ");
|
||||
Object[] elements = hashtable.entrySet().toArray();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
try {
|
||||
buffer.append('\n');
|
||||
element = (GSSCredentialSpi)
|
||||
((Map.Entry)elements[i]).getValue();
|
||||
buffer.append(element.getName());
|
||||
buffer.append(' ');
|
||||
buffer.append(element.getMechanism());
|
||||
buffer.append(element.isInitiatorCredential() ?
|
||||
" Initiate" : "");
|
||||
buffer.append(element.isAcceptorCredential() ?
|
||||
" Accept" : "");
|
||||
buffer.append(" [");
|
||||
buffer.append(element.getClass());
|
||||
buffer.append(']');
|
||||
} catch (GSSException e) {
|
||||
// skip to next element
|
||||
}
|
||||
}
|
||||
buffer.append(']');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
static class SearchKey {
|
||||
private Oid mechOid = null;
|
||||
private int usage = GSSCredential.INITIATE_AND_ACCEPT;
|
||||
public SearchKey(Oid mechOid, int usage) {
|
||||
|
||||
this.mechOid = mechOid;
|
||||
this.usage = usage;
|
||||
}
|
||||
public Oid getMech() {
|
||||
return mechOid;
|
||||
}
|
||||
public int getUsage() {
|
||||
return usage;
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (! (other instanceof SearchKey))
|
||||
return false;
|
||||
SearchKey that = (SearchKey) other;
|
||||
return ((this.mechOid.equals(that.mechOid)) &&
|
||||
(this.usage == that.usage));
|
||||
}
|
||||
public int hashCode() {
|
||||
return mechOid.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
89
jdkSrc/jdk8/sun/security/jgss/GSSExceptionImpl.java
Normal file
89
jdkSrc/jdk8/sun/security/jgss/GSSExceptionImpl.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
|
||||
/**
|
||||
* This class helps overcome a limitation of the org.ietf.jgss.GSSException
|
||||
* class that does not allow the thrower to set a string corresponding to
|
||||
* the major code.
|
||||
*/
|
||||
public class GSSExceptionImpl extends GSSException {
|
||||
|
||||
private static final long serialVersionUID = 4251197939069005575L;
|
||||
|
||||
private String majorMessage;
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode as well as the mech oid that
|
||||
* will be appended to the standard message defined in its super class.
|
||||
*/
|
||||
GSSExceptionImpl(int majorCode, Oid mech) {
|
||||
super(majorCode);
|
||||
this.majorMessage = super.getMajorString() + ": " + mech;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode as well as the message that
|
||||
* corresponds to it.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, String majorMessage) {
|
||||
super(majorCode);
|
||||
this.majorMessage = majorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode and the exception cause.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, Exception cause) {
|
||||
super(majorCode);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode, the message that
|
||||
* corresponds to it, and the exception cause.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, String majorMessage,
|
||||
Exception cause) {
|
||||
this(majorCode, majorMessage);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message that was embedded in this object, otherwise it
|
||||
* returns the default message that an org.ietf.jgss.GSSException
|
||||
* generates.
|
||||
*/
|
||||
public String getMessage() {
|
||||
if (majorMessage != null)
|
||||
return majorMessage;
|
||||
else
|
||||
return super.getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
345
jdkSrc/jdk8/sun/security/jgss/GSSHeader.java
Normal file
345
jdkSrc/jdk8/sun/security/jgss/GSSHeader.java
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.GSSException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* This class represents the mechanism independent part of a GSS-API
|
||||
* context establishment token. Some mechanisms may choose to encode
|
||||
* all subsequent tokens as well such that they start with an encoding
|
||||
* of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism
|
||||
* uses this header for all GSS-API tokens.
|
||||
* <p>
|
||||
* The format is specified in RFC 2743 section 3.1.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
/*
|
||||
* The RFC states that implementations should explicitly follow the
|
||||
* encoding scheme descibed in this section rather than use ASN.1
|
||||
* compilers. However, we should consider removing duplicate ASN.1
|
||||
* like code from here and depend on sun.security.util if possible.
|
||||
*/
|
||||
|
||||
public class GSSHeader {
|
||||
|
||||
private ObjectIdentifier mechOid = null;
|
||||
private byte[] mechOidBytes = null;
|
||||
private int mechTokenLength = 0;
|
||||
|
||||
/**
|
||||
* The tag defined in the GSS-API mechanism independent token
|
||||
* format.
|
||||
*/
|
||||
public static final int TOKEN_ID=0x60;
|
||||
|
||||
/**
|
||||
* Creates a GSSHeader instance whose encoding can be used as the
|
||||
* prefix for a particular mechanism token.
|
||||
* @param mechOid the Oid of the mechanism which generated the token
|
||||
* @param mechTokenLength the length of the subsequent portion that
|
||||
* the mechanism will be adding.
|
||||
*/
|
||||
public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength)
|
||||
throws IOException {
|
||||
|
||||
this.mechOid = mechOid;
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putOID(mechOid);
|
||||
mechOidBytes = temp.toByteArray();
|
||||
this.mechTokenLength = mechTokenLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a GSSHeader from an InputStream. Typically this would be
|
||||
* used as part of reading the complete token from an InputStream
|
||||
* that is obtained from a socket.
|
||||
*/
|
||||
public GSSHeader(InputStream is)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// debug("Parsing GSS token: ");
|
||||
|
||||
int tag = is.read();
|
||||
|
||||
// debug("tag=" + tag);
|
||||
|
||||
if (tag != TOKEN_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"GSSHeader did not find the right tag");
|
||||
|
||||
int length = getLength(is);
|
||||
|
||||
DerValue temp = new DerValue(is);
|
||||
mechOidBytes = temp.toByteArray();
|
||||
mechOid = temp.getOID();
|
||||
// debug (" oid=" + mechOid);
|
||||
|
||||
// debug (" len starting with oid=" + length);
|
||||
mechTokenLength = length - mechOidBytes.length;
|
||||
|
||||
// debug(" mechToken length=" + mechTokenLength);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the Oid stored in this GSSHeader instance.
|
||||
* @return the Oid of the mechanism.
|
||||
*/
|
||||
public ObjectIdentifier getOid() {
|
||||
return mechOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the length of the mechanism specific token that
|
||||
* will follow the encoding of this GSSHeader instance.
|
||||
* @return the length of the mechanism specific token portion that
|
||||
* will follow this GSSHeader.
|
||||
*/
|
||||
public int getMechTokenLength() {
|
||||
return mechTokenLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the length of the encoding of this GSSHeader.
|
||||
* @return the lenght of the encoding of this GSSHeader instance.
|
||||
*/
|
||||
public int getLength() {
|
||||
int lenField = mechOidBytes.length + mechTokenLength;
|
||||
return (1 + getLenFieldSize(lenField) + mechOidBytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine what the maximum possible mechanism token
|
||||
* size is if the complete GSSToken returned to the application
|
||||
* (including a GSSHeader) is not to exceed some pre-determined
|
||||
* value in size.
|
||||
* @param mechOid the Oid of the mechanism that will generate
|
||||
* this GSS-API token
|
||||
* @param maxTotalSize the pre-determined value that serves as a
|
||||
* maximum size for the complete GSS-API token (including a
|
||||
* GSSHeader)
|
||||
* @return the maximum size of mechanism token that can be used
|
||||
* so as to not exceed maxTotalSize with the GSS-API token
|
||||
*/
|
||||
public static int getMaxMechTokenSize(ObjectIdentifier mechOid,
|
||||
int maxTotalSize) {
|
||||
|
||||
int mechOidBytesSize = 0;
|
||||
try {
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putOID(mechOid);
|
||||
mechOidBytesSize = temp.toByteArray().length;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
// Subtract bytes needed for 0x60 tag and mechOidBytes
|
||||
maxTotalSize -= (1 + mechOidBytesSize);
|
||||
|
||||
// Subtract maximum len bytes
|
||||
maxTotalSize -= 5;
|
||||
|
||||
return maxTotalSize;
|
||||
|
||||
/*
|
||||
* Len field and mechanism token must fit in remaining
|
||||
* space. The range of the len field that we allow is
|
||||
* 1 through 5.
|
||||
*
|
||||
|
||||
int mechTokenSize = 0;
|
||||
for (int lenFieldSize = 1; lenFieldSize <= 5;
|
||||
lenFieldSize++) {
|
||||
mechTokenSize = maxTotalSize - lenFieldSize;
|
||||
if (getLenFieldSize(mechTokenSize + mechOidBytesSize +
|
||||
lenFieldSize) <= lenFieldSize)
|
||||
break;
|
||||
}
|
||||
|
||||
return mechTokenSize;
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the number of bytes that will be need to encode
|
||||
* the length field of the GSSHeader.
|
||||
*/
|
||||
private int getLenFieldSize(int len) {
|
||||
int retVal = 1;
|
||||
if (len < 128) {
|
||||
retVal=1;
|
||||
} else if (len < (1 << 8)) {
|
||||
retVal=2;
|
||||
} else if (len < (1 << 16)) {
|
||||
retVal=3;
|
||||
} else if (len < (1 << 24)) {
|
||||
retVal=4;
|
||||
} else {
|
||||
retVal=5; // See getMaxMechTokenSize
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this GSSHeader instance onto the provided OutputStream.
|
||||
* @param os the OutputStream to which the token should be written.
|
||||
* @return the number of bytes that are output as a result of this
|
||||
* encoding
|
||||
*/
|
||||
public int encode(OutputStream os) throws IOException {
|
||||
int retVal = 1 + mechOidBytes.length;
|
||||
os.write(TOKEN_ID);
|
||||
int length = mechOidBytes.length + mechTokenLength;
|
||||
retVal += putLength(length, os);
|
||||
os.write(mechOidBytes);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a length from the input stream, allowing for at most 32 bits of
|
||||
* encoding to be used. (Not the same as getting a tagged integer!)
|
||||
*
|
||||
* @return the length or -1 if indefinite length found.
|
||||
* @exception IOException on parsing error or unsupported lengths.
|
||||
*/
|
||||
// shameless lifted from sun.security.util.DerInputStream.
|
||||
private int getLength(InputStream in) throws IOException {
|
||||
return getLength(in.read(), in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a length from the input stream, allowing for at most 32 bits of
|
||||
* encoding to be used. (Not the same as getting a tagged integer!)
|
||||
*
|
||||
* @return the length or -1 if indefinite length found.
|
||||
* @exception IOException on parsing error or unsupported lengths.
|
||||
*/
|
||||
// shameless lifted from sun.security.util.DerInputStream.
|
||||
private int getLength(int lenByte, InputStream in) throws IOException {
|
||||
int value, tmp;
|
||||
|
||||
tmp = lenByte;
|
||||
if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
|
||||
value = tmp;
|
||||
} else { // long form or indefinite
|
||||
tmp &= 0x07f;
|
||||
|
||||
/*
|
||||
* NOTE: tmp == 0 indicates indefinite length encoded data.
|
||||
* tmp > 4 indicates more than 4Gb of data.
|
||||
*/
|
||||
if (tmp == 0)
|
||||
return -1;
|
||||
if (tmp < 0 || tmp > 4)
|
||||
throw new IOException("DerInputStream.getLength(): lengthTag="
|
||||
+ tmp + ", "
|
||||
+ ((tmp < 0) ? "incorrect DER encoding." : "too big."));
|
||||
|
||||
for (value = 0; tmp > 0; tmp --) {
|
||||
value <<= 8;
|
||||
value += 0x0ff & in.read();
|
||||
}
|
||||
if (value < 0) {
|
||||
throw new IOException("Invalid length bytes");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the encoding of the length in the specified stream.
|
||||
*
|
||||
* @params len the length of the attribute.
|
||||
* @param out the outputstream to write the length to
|
||||
* @return the number of bytes written
|
||||
* @exception IOException on writing errors.
|
||||
*/
|
||||
// Shameless lifted from sun.security.util.DerOutputStream.
|
||||
private int putLength(int len, OutputStream out) throws IOException {
|
||||
int retVal = 0;
|
||||
if (len < 128) {
|
||||
out.write((byte)len);
|
||||
retVal=1;
|
||||
|
||||
} else if (len < (1 << 8)) {
|
||||
out.write((byte)0x081);
|
||||
out.write((byte)len);
|
||||
retVal=2;
|
||||
|
||||
} else if (len < (1 << 16)) {
|
||||
out.write((byte)0x082);
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=3;
|
||||
|
||||
} else if (len < (1 << 24)) {
|
||||
out.write((byte)0x083);
|
||||
out.write((byte)(len >> 16));
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=4;
|
||||
|
||||
} else {
|
||||
out.write((byte)0x084);
|
||||
out.write((byte)(len >> 24));
|
||||
out.write((byte)(len >> 16));
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=5;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// XXX Call these two in some central class
|
||||
private void debug(String str) {
|
||||
System.err.print(str);
|
||||
}
|
||||
|
||||
private String getHexBytes(byte[] bytes, int len)
|
||||
throws IOException {
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
int b1 = (bytes[i]>>4) & 0x0f;
|
||||
int b2 = bytes[i] & 0x0f;
|
||||
|
||||
sb.append(Integer.toHexString(b1));
|
||||
sb.append(Integer.toHexString(b2));
|
||||
sb.append(' ');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/sun/security/jgss/GSSManagerImpl.java
Normal file
254
jdkSrc/jdk8/sun/security/jgss/GSSManagerImpl.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* This class provides the default implementation of the GSSManager
|
||||
* interface.
|
||||
*/
|
||||
public class GSSManagerImpl extends GSSManager {
|
||||
|
||||
// Undocumented property
|
||||
private static final String USE_NATIVE_PROP =
|
||||
"sun.security.jgss.native";
|
||||
private static final Boolean USE_NATIVE;
|
||||
|
||||
static {
|
||||
USE_NATIVE =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return Boolean.valueOf(System.getProperty
|
||||
(USE_NATIVE_PROP));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private ProviderList list;
|
||||
|
||||
// Used by java SPNEGO impl to make sure native is disabled
|
||||
public GSSManagerImpl(GSSCaller caller, boolean useNative) {
|
||||
list = new ProviderList(caller, useNative);
|
||||
}
|
||||
|
||||
// Used by HTTP/SPNEGO NegotiatorImpl
|
||||
public GSSManagerImpl(GSSCaller caller) {
|
||||
list = new ProviderList(caller, USE_NATIVE);
|
||||
}
|
||||
|
||||
public GSSManagerImpl() {
|
||||
list = new ProviderList(GSSCaller.CALLER_UNKNOWN, USE_NATIVE);
|
||||
}
|
||||
|
||||
public Oid[] getMechs(){
|
||||
return list.getMechs();
|
||||
}
|
||||
|
||||
public Oid[] getNamesForMech(Oid mech)
|
||||
throws GSSException {
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameTypes().clone();
|
||||
}
|
||||
|
||||
public Oid[] getMechsForName(Oid nameType){
|
||||
Oid[] mechs = list.getMechs();
|
||||
Oid[] retVal = new Oid[mechs.length];
|
||||
int pos = 0;
|
||||
|
||||
// Compatibility with RFC 2853 old NT_HOSTBASED_SERVICE value.
|
||||
if (nameType.equals(GSSNameImpl.oldHostbasedServiceName)) {
|
||||
nameType = GSSName.NT_HOSTBASED_SERVICE;
|
||||
}
|
||||
|
||||
// Iterate thru all mechs in GSS
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
// what nametypes does this mech support?
|
||||
Oid mech = mechs[i];
|
||||
try {
|
||||
Oid[] namesForMech = getNamesForMech(mech);
|
||||
// Is the desired Oid present in that list?
|
||||
if (nameType.containedIn(namesForMech)) {
|
||||
retVal[pos++] = mech;
|
||||
}
|
||||
} catch (GSSException e) {
|
||||
// Squelch it and just skip over this mechanism
|
||||
GSSUtil.debug("Skip " + mech +
|
||||
": error retrieving supported name types");
|
||||
}
|
||||
}
|
||||
|
||||
// Trim the list if needed
|
||||
if (pos < retVal.length) {
|
||||
Oid[] temp = new Oid[pos];
|
||||
for (int i = 0; i < pos; i++)
|
||||
temp[i] = retVal[i];
|
||||
retVal = temp;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public GSSName createName(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, nameStr, nameType);
|
||||
}
|
||||
|
||||
public GSSName createName(byte name[], Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, name, nameType);
|
||||
}
|
||||
|
||||
public GSSName createName(String nameStr, Oid nameType,
|
||||
Oid mech) throws GSSException {
|
||||
return new GSSNameImpl(this, nameStr, nameType, mech);
|
||||
}
|
||||
|
||||
public GSSName createName(byte name[], Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, name, nameType, mech);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, usage);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(GSSName aName,
|
||||
int lifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, aName, lifetime, mech, usage);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(GSSName aName,
|
||||
int lifetime, Oid mechs[], int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, aName, lifetime, mechs, usage);
|
||||
}
|
||||
|
||||
public GSSContext createContext(GSSName peer, Oid mech,
|
||||
GSSCredential myCred, int lifetime)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, peer, mech, myCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContext createContext(GSSCredential myCred)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, myCred);
|
||||
}
|
||||
|
||||
public GSSContext createContext(byte[] interProcessToken)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, interProcessToken);
|
||||
}
|
||||
|
||||
public void addProviderAtFront(Provider p, Oid mech)
|
||||
throws GSSException {
|
||||
list.addProviderAtFront(p, mech);
|
||||
}
|
||||
|
||||
public void addProviderAtEnd(Provider p, Oid mech)
|
||||
throws GSSException {
|
||||
list.addProviderAtEnd(p, mech);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name, int initLifetime,
|
||||
int acceptLifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getCredentialElement(name, initLifetime,
|
||||
acceptLifetime, usage);
|
||||
}
|
||||
|
||||
// Used by java SPNEGO impl
|
||||
public GSSNameSpi getNameElement(String name, Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
// Just use the most preferred MF impl assuming GSSNameSpi
|
||||
// objects are interoperable among providers
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameElement(name, nameType);
|
||||
}
|
||||
|
||||
// Used by java SPNEGO impl
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
// Just use the most preferred MF impl assuming GSSNameSpi
|
||||
// objects are interoperable among providers
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameElement(name, nameType);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred,
|
||||
int lifetime, Oid mech)
|
||||
throws GSSException {
|
||||
Provider p = null;
|
||||
if (myInitiatorCred != null) {
|
||||
p = myInitiatorCred.getProvider();
|
||||
}
|
||||
MechanismFactory factory = list.getMechFactory(mech, p);
|
||||
return factory.getMechanismContext(peer, myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
Provider p = null;
|
||||
if (myAcceptorCred != null) {
|
||||
p = myAcceptorCred.getProvider();
|
||||
}
|
||||
MechanismFactory factory = list.getMechFactory(mech, p);
|
||||
return factory.getMechanismContext(myAcceptorCred);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
if ((exportedContext == null) || (exportedContext.length == 0)) {
|
||||
throw new GSSException(GSSException.NO_CONTEXT);
|
||||
}
|
||||
GSSContextSpi result = null;
|
||||
|
||||
// Only allow context import with native provider since JGSS
|
||||
// still has not defined its own interprocess token format
|
||||
Oid[] mechs = list.getMechs();
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
MechanismFactory factory = list.getMechFactory(mechs[i]);
|
||||
if (factory.getProvider().getName().equals("SunNativeGSS")) {
|
||||
result = factory.getMechanismContext(exportedContext);
|
||||
if (result != null) break;
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
throw new GSSException(GSSException.UNAVAILABLE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
507
jdkSrc/jdk8/sun/security/jgss/GSSNameImpl.java
Normal file
507
jdkSrc/jdk8/sun/security/jgss/GSSNameImpl.java
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.util.Set;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
|
||||
/**
|
||||
* This is the implementation class for GSSName. Conceptually the
|
||||
* GSSName is a container with mechanism specific name elements. Each
|
||||
* name element is a representation of how that particular mechanism
|
||||
* would canonicalize this principal.
|
||||
*
|
||||
* Generally a GSSName is created by an application when it supplies
|
||||
* a sequence of bytes and a nametype that helps each mechanism
|
||||
* decide how to interpret those bytes.
|
||||
*
|
||||
* It is not necessary to create name elements for each available
|
||||
* mechanism at the time the application creates the GSSName. This
|
||||
* implementation does this lazily, as and when name elements for
|
||||
* mechanisms are required to be handed out. (Generally, other GSS
|
||||
* classes like GSSContext and GSSCredential request specific
|
||||
* elements depending on the mechanisms that they are dealing with.)
|
||||
* Assume that getting a mechanism to parse the applciation specified
|
||||
* bytes is an expensive call.
|
||||
*
|
||||
* When a GSSName is canonicalized wrt some mechanism, it is supposed
|
||||
* to discard all elements of other mechanisms and retain only the
|
||||
* element for this mechanism. In GSS terminology this is called a
|
||||
* Mechanism Name or MN. This implementation tries to retain the
|
||||
* application provided bytes and name type just in case the MN is
|
||||
* asked to produce an element for a mechanism that is different.
|
||||
*
|
||||
* When a GSSName is to be exported, the name element for the desired
|
||||
* mechanism is converted to a byte representation and written
|
||||
* out. It might happen that a name element for that mechanism cannot
|
||||
* be obtained. This happens when the mechanism is just not supported
|
||||
* in this GSS-API or when the mechanism is supported but bytes
|
||||
* corresponding to the nametypes that it understands are not
|
||||
* available in this GSSName.
|
||||
*
|
||||
* This class is safe for sharing. Each retrieval of a name element
|
||||
* from getElement() might potentially add a new element to the
|
||||
* hashmap of elements, but getElement() is synchronized.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class GSSNameImpl implements GSSName {
|
||||
|
||||
/**
|
||||
* The old Oid used in RFC 2853. Now supported as
|
||||
* input parameters in:
|
||||
*
|
||||
* 1. The four overloaded GSSManager.createName(*) methods
|
||||
* 2. GSSManager.getMechsForName(Oid)
|
||||
*
|
||||
* Note that even if a GSSName is created with this old Oid,
|
||||
* its internal name type and getStringNameType() output are
|
||||
* always the new value.
|
||||
*/
|
||||
final static Oid oldHostbasedServiceName;
|
||||
|
||||
static {
|
||||
Oid tmp = null;
|
||||
try {
|
||||
tmp = new Oid("1.3.6.1.5.6.2");
|
||||
} catch (Exception e) {
|
||||
// should never happen
|
||||
}
|
||||
oldHostbasedServiceName = tmp;
|
||||
}
|
||||
|
||||
private GSSManagerImpl gssManager = null;
|
||||
|
||||
/*
|
||||
* Store whatever the application passed in. We will use this to
|
||||
* get individual mechanisms to create name elements as and when
|
||||
* needed.
|
||||
* Store both the String and the byte[]. Leave I18N to the
|
||||
* mechanism by allowing it to extract bytes from the String!
|
||||
*/
|
||||
|
||||
private String appNameStr = null;
|
||||
private byte[] appNameBytes = null;
|
||||
private Oid appNameType = null;
|
||||
|
||||
/*
|
||||
* When we figure out what the printable name would be, we store
|
||||
* both the name and its type.
|
||||
*/
|
||||
|
||||
private String printableName = null;
|
||||
private Oid printableNameType = null;
|
||||
|
||||
private HashMap<Oid, GSSNameSpi> elements = null;
|
||||
private GSSNameSpi mechElement = null;
|
||||
|
||||
static GSSNameImpl wrapElement(GSSManagerImpl gssManager,
|
||||
GSSNameSpi mechElement) throws GSSException {
|
||||
return (mechElement == null ?
|
||||
null : new GSSNameImpl(gssManager, mechElement));
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager, GSSNameSpi mechElement) {
|
||||
this.gssManager = gssManager;
|
||||
appNameStr = printableName = mechElement.toString();
|
||||
appNameType = printableNameType = mechElement.getStringNameType();
|
||||
this.mechElement = mechElement;
|
||||
elements = new HashMap<Oid, GSSNameSpi>(1);
|
||||
elements.put(mechElement.getMechanism(), this.mechElement);
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager,
|
||||
Object appName,
|
||||
Oid appNameType)
|
||||
throws GSSException {
|
||||
this(gssManager, appName, appNameType, null);
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager,
|
||||
Object appName,
|
||||
Oid appNameType,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
|
||||
if (oldHostbasedServiceName.equals(appNameType)) {
|
||||
appNameType = GSSName.NT_HOSTBASED_SERVICE;
|
||||
}
|
||||
if (appName == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Cannot import null name");
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
if (NT_EXPORT_NAME.equals(appNameType)) {
|
||||
importName(gssManager, appName);
|
||||
} else {
|
||||
init(gssManager, appName, appNameType, mech);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(GSSManagerImpl gssManager,
|
||||
Object appName, Oid appNameType,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
|
||||
this.gssManager = gssManager;
|
||||
this.elements =
|
||||
new HashMap<Oid, GSSNameSpi>(gssManager.getMechs().length);
|
||||
|
||||
if (appName instanceof String) {
|
||||
this.appNameStr = (String) appName;
|
||||
/*
|
||||
* If appNameType is null, then the nametype for this printable
|
||||
* string is determined only by interrogating the
|
||||
* mechanism. Thus, defer the setting of printableName and
|
||||
* printableNameType till later.
|
||||
*/
|
||||
if (appNameType != null) {
|
||||
printableName = appNameStr;
|
||||
printableNameType = appNameType;
|
||||
}
|
||||
} else {
|
||||
this.appNameBytes = (byte[]) appName;
|
||||
}
|
||||
|
||||
this.appNameType = appNameType;
|
||||
|
||||
mechElement = getElement(mech);
|
||||
|
||||
/*
|
||||
* printableName will be null if appName was in a byte[] or if
|
||||
* appName was in a String but appNameType was null.
|
||||
*/
|
||||
if (printableName == null) {
|
||||
printableName = mechElement.toString();
|
||||
printableNameType = mechElement.getStringNameType();
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point the GSSNameImpl has the following set:
|
||||
* appNameStr or appNameBytes
|
||||
* appNameType (could be null)
|
||||
* printableName
|
||||
* printableNameType
|
||||
* mechElement (which also exists in the hashmap of elements)
|
||||
*/
|
||||
}
|
||||
|
||||
private void importName(GSSManagerImpl gssManager,
|
||||
Object appName)
|
||||
throws GSSException {
|
||||
|
||||
int pos = 0;
|
||||
byte[] bytes = null;
|
||||
|
||||
if (appName instanceof String) {
|
||||
try {
|
||||
bytes = ((String) appName).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Won't happen
|
||||
}
|
||||
} else
|
||||
bytes = (byte[]) appName;
|
||||
|
||||
if ((bytes[pos++] != 0x04) ||
|
||||
(bytes[pos++] != 0x01))
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name token id is corrupted!");
|
||||
|
||||
int oidLen = (((0xFF & bytes[pos++]) << 8) |
|
||||
(0xFF & bytes[pos++]));
|
||||
ObjectIdentifier temp = null;
|
||||
try {
|
||||
DerInputStream din = new DerInputStream(bytes, pos,
|
||||
oidLen);
|
||||
temp = new ObjectIdentifier(din);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name Object identifier is corrupted!");
|
||||
}
|
||||
Oid oid = new Oid(temp.toString());
|
||||
pos += oidLen;
|
||||
int mechPortionLen = (((0xFF & bytes[pos++]) << 24) |
|
||||
((0xFF & bytes[pos++]) << 16) |
|
||||
((0xFF & bytes[pos++]) << 8) |
|
||||
(0xFF & bytes[pos++]));
|
||||
if (mechPortionLen < 0 || pos > bytes.length - mechPortionLen) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name mech name is corrupted!");
|
||||
}
|
||||
byte[] mechPortion = new byte[mechPortionLen];
|
||||
System.arraycopy(bytes, pos, mechPortion, 0, mechPortionLen);
|
||||
|
||||
init(gssManager, mechPortion, NT_EXPORT_NAME, oid);
|
||||
}
|
||||
|
||||
public GSSName canonicalize(Oid mech) throws GSSException {
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
return wrapElement(gssManager, getElement(mech));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method may return false negatives. But if it says two
|
||||
* names are equals, then there is some mechanism that
|
||||
* authenticates them as the same principal.
|
||||
*/
|
||||
public boolean equals(GSSName other) throws GSSException {
|
||||
|
||||
if (this.isAnonymous() || other.isAnonymous())
|
||||
return false;
|
||||
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
if (! (other instanceof GSSNameImpl))
|
||||
return equals(gssManager.createName(other.toString(),
|
||||
other.getStringNameType()));
|
||||
|
||||
/*
|
||||
* XXX Do a comparison of the appNameStr/appNameBytes if
|
||||
* available. If that fails, then proceed with this test.
|
||||
*/
|
||||
|
||||
GSSNameImpl that = (GSSNameImpl) other;
|
||||
|
||||
GSSNameSpi myElement = this.mechElement;
|
||||
GSSNameSpi element = that.mechElement;
|
||||
|
||||
/*
|
||||
* XXX If they are not of the same mechanism type, convert both to
|
||||
* Kerberos since it is guaranteed to be present.
|
||||
*/
|
||||
if ((myElement == null) && (element != null)) {
|
||||
myElement = this.getElement(element.getMechanism());
|
||||
} else if ((myElement != null) && (element == null)) {
|
||||
element = that.getElement(myElement.getMechanism());
|
||||
}
|
||||
|
||||
if (myElement != null && element != null) {
|
||||
return myElement.equals(element);
|
||||
}
|
||||
|
||||
if ((this.appNameType != null) &&
|
||||
(that.appNameType != null)) {
|
||||
if (!this.appNameType.equals(that.appNameType)) {
|
||||
return false;
|
||||
}
|
||||
byte[] myBytes = null;
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
myBytes =
|
||||
(this.appNameStr != null ?
|
||||
this.appNameStr.getBytes("UTF-8") :
|
||||
this.appNameBytes);
|
||||
bytes =
|
||||
(that.appNameStr != null ?
|
||||
that.appNameStr.getBytes("UTF-8") :
|
||||
that.appNameBytes);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Won't happen
|
||||
}
|
||||
|
||||
return Arrays.equals(myBytes, bytes);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSName.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
/*
|
||||
* XXX
|
||||
* In order to get this to work reliably and properly(!), obtain a
|
||||
* Kerberos name element for the name and then call hashCode on its
|
||||
* string representation. But this cannot be done if the nametype
|
||||
* is not one of those supported by the Kerberos provider and hence
|
||||
* this name cannot be imported by Kerberos. In that case return a
|
||||
* constant value!
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean equals(Object another) {
|
||||
|
||||
try {
|
||||
// XXX This can lead to an infinite loop. Extract info
|
||||
// and create a GSSNameImpl with it.
|
||||
|
||||
if (another instanceof GSSName)
|
||||
return equals((GSSName) another);
|
||||
} catch (GSSException e) {
|
||||
// Squelch it and return false
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flat name representation for this object. The name
|
||||
* format is defined in RFC 2743:
|
||||
*<pre>
|
||||
* Length Name Description
|
||||
* 2 TOK_ID Token Identifier
|
||||
* For exported name objects, this
|
||||
* must be hex 04 01.
|
||||
* 2 MECH_OID_LEN Length of the Mechanism OID
|
||||
* MECH_OID_LEN MECH_OID Mechanism OID, in DER
|
||||
* 4 NAME_LEN Length of name
|
||||
* NAME_LEN NAME Exported name; format defined in
|
||||
* applicable mechanism draft.
|
||||
*</pre>
|
||||
*
|
||||
* Note that it is not required to canonicalize a name before
|
||||
* calling export(). i.e., the name need not be an MN. If it is
|
||||
* not an MN, an implementation defined algorithm can be used for
|
||||
* choosing the mechanism which should export this name.
|
||||
*
|
||||
* @return the flat name representation for this object
|
||||
* @exception GSSException with major codes NAME_NOT_MN, BAD_NAME,
|
||||
* BAD_NAME, FAILURE.
|
||||
*/
|
||||
public byte[] export() throws GSSException {
|
||||
|
||||
if (mechElement == null) {
|
||||
/* Use default mech */
|
||||
mechElement = getElement(ProviderList.DEFAULT_MECH_OID);
|
||||
}
|
||||
|
||||
byte[] mechPortion = mechElement.export();
|
||||
byte[] oidBytes = null;
|
||||
ObjectIdentifier oid = null;
|
||||
|
||||
try {
|
||||
oid = new ObjectIdentifier
|
||||
(mechElement.getMechanism().toString());
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Invalid OID String ");
|
||||
}
|
||||
DerOutputStream dout = new DerOutputStream();
|
||||
try {
|
||||
dout.putOID(oid);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Could not ASN.1 Encode "
|
||||
+ oid.toString());
|
||||
}
|
||||
oidBytes = dout.toByteArray();
|
||||
|
||||
byte[] retVal = new byte[2
|
||||
+ 2 + oidBytes.length
|
||||
+ 4 + mechPortion.length];
|
||||
int pos = 0;
|
||||
retVal[pos++] = 0x04;
|
||||
retVal[pos++] = 0x01;
|
||||
retVal[pos++] = (byte) (oidBytes.length>>>8);
|
||||
retVal[pos++] = (byte) oidBytes.length;
|
||||
System.arraycopy(oidBytes, 0, retVal, pos, oidBytes.length);
|
||||
pos += oidBytes.length;
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>24);
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>16);
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>8);
|
||||
retVal[pos++] = (byte) mechPortion.length;
|
||||
System.arraycopy(mechPortion, 0, retVal, pos, mechPortion.length);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return printableName;
|
||||
|
||||
}
|
||||
|
||||
public Oid getStringNameType() throws GSSException {
|
||||
return printableNameType;
|
||||
}
|
||||
|
||||
public boolean isAnonymous() {
|
||||
if (printableNameType == null) {
|
||||
return false;
|
||||
} else {
|
||||
return GSSName.NT_ANONYMOUS.equals(printableNameType);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMN() {
|
||||
return true; // Since always canonicalized for some mech
|
||||
}
|
||||
|
||||
public synchronized GSSNameSpi getElement(Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
GSSNameSpi retVal = elements.get(mechOid);
|
||||
|
||||
if (retVal == null) {
|
||||
if (appNameStr != null) {
|
||||
retVal = gssManager.getNameElement
|
||||
(appNameStr, appNameType, mechOid);
|
||||
} else {
|
||||
retVal = gssManager.getNameElement
|
||||
(appNameBytes, appNameType, mechOid);
|
||||
}
|
||||
elements.put(mechOid, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
Set<GSSNameSpi> getElements() {
|
||||
return new HashSet<GSSNameSpi>(elements.values());
|
||||
}
|
||||
|
||||
private static String getNameTypeStr(Oid nameTypeOid) {
|
||||
|
||||
if (nameTypeOid == null)
|
||||
return "(NT is null)";
|
||||
|
||||
if (nameTypeOid.equals(NT_USER_NAME))
|
||||
return "NT_USER_NAME";
|
||||
if (nameTypeOid.equals(NT_HOSTBASED_SERVICE))
|
||||
return "NT_HOSTBASED_SERVICE";
|
||||
if (nameTypeOid.equals(NT_EXPORT_NAME))
|
||||
return "NT_EXPORT_NAME";
|
||||
if (nameTypeOid.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
|
||||
return "NT_GSS_KRB5_PRINCIPAL";
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
231
jdkSrc/jdk8/sun/security/jgss/GSSToken.java
Normal file
231
jdkSrc/jdk8/sun/security/jgss/GSSToken.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Utilities for processing GSS Tokens.
|
||||
*
|
||||
*/
|
||||
|
||||
public abstract class GSSToken {
|
||||
|
||||
/**
|
||||
* Copies an integer value to a byte array in little endian form.
|
||||
* @param value the integer value to write
|
||||
* @param array the byte array into which the integer must be copied. It
|
||||
* is assumed that the array will be large enough to hold the 4 bytes of
|
||||
* the integer.
|
||||
*/
|
||||
public static final void writeLittleEndian(int value, byte[] array) {
|
||||
writeLittleEndian(value, array, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies an integer value to a byte array in little endian form.
|
||||
* @param value the integer value to write
|
||||
* @param array the byte array into which the integer must be copied. It
|
||||
* is assumed that the array will be large enough to hold the 4 bytes of
|
||||
* the integer.
|
||||
* @param pos the position at which to start writing
|
||||
*/
|
||||
public static final void writeLittleEndian(int value, byte[] array,
|
||||
int pos) {
|
||||
array[pos++] = (byte)(value);
|
||||
array[pos++] = (byte)((value>>>8));
|
||||
array[pos++] = (byte)((value>>>16));
|
||||
array[pos++] = (byte)((value>>>24));
|
||||
}
|
||||
|
||||
public static final void writeBigEndian(int value, byte[] array) {
|
||||
writeBigEndian(value, array, 0);
|
||||
}
|
||||
|
||||
public static final void writeBigEndian(int value, byte[] array,
|
||||
int pos) {
|
||||
array[pos++] = (byte)((value>>>24));
|
||||
array[pos++] = (byte)((value>>>16));
|
||||
array[pos++] = (byte)((value>>>8));
|
||||
array[pos++] = (byte)(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer value from a byte array in little endian form. This
|
||||
* method allows the reading of two byte values as well as four bytes
|
||||
* values both of which are needed in the Kerberos v5 GSS-API mechanism.
|
||||
*
|
||||
* @param data the array containing the bytes of the integer value
|
||||
* @param pos the offset in the array
|
||||
* @param size the number of bytes to read from the array.
|
||||
* @return the integer value
|
||||
*/
|
||||
public static final int readLittleEndian(byte[] data, int pos, int size) {
|
||||
int retVal = 0;
|
||||
int shifter = 0;
|
||||
while (size > 0) {
|
||||
retVal += (data[pos] & 0xff) << shifter;
|
||||
shifter += 8;
|
||||
pos++;
|
||||
size--;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static final int readBigEndian(byte[] data, int pos, int size) {
|
||||
int retVal = 0;
|
||||
int shifter = (size-1)*8;
|
||||
while (size > 0) {
|
||||
retVal += (data[pos] & 0xff) << shifter;
|
||||
shifter -= 8;
|
||||
pos++;
|
||||
size--;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a two byte integer value to a OutputStream.
|
||||
*
|
||||
* @param val the integer value. It will lose the high-order two bytes.
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException if an error occurs while writing to the OutputStream
|
||||
*/
|
||||
public static final void writeInt(int val, OutputStream os)
|
||||
throws IOException {
|
||||
os.write(val>>>8);
|
||||
os.write(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a two byte integer value to a byte array.
|
||||
*
|
||||
* @param val the integer value. It will lose the high-order two bytes.
|
||||
* @param dest the byte array to write to
|
||||
* @param pos the offset to start writing to
|
||||
*/
|
||||
public static final int writeInt(int val, byte[] dest, int pos) {
|
||||
dest[pos++] = (byte)(val>>>8);
|
||||
dest[pos++] = (byte)val;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a two byte integer value from an InputStream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @return the integer value
|
||||
* @throws IOException if some errors occurs while reading the integer
|
||||
* bytes.
|
||||
*/
|
||||
public static final int readInt(InputStream is) throws IOException {
|
||||
return (((0xFF & is.read()) << 8)
|
||||
| (0xFF & is.read()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a two byte integer value from a byte array.
|
||||
*
|
||||
* @param src the byte arra to read from
|
||||
* @param pos the offset to start reading from
|
||||
* @return the integer value
|
||||
*/
|
||||
public static final int readInt(byte[] src, int pos) {
|
||||
return ((0xFF & src[pos])<<8 | (0xFF & src[pos+1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks till the required number of bytes have been read from the
|
||||
* input stream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param buffer the buffer to store the bytes into
|
||||
* @throws EOFException if EOF is reached before all bytes are
|
||||
* read.
|
||||
* @throws IOException is an error occurs while reading
|
||||
*/
|
||||
public static final void readFully(InputStream is, byte[] buffer)
|
||||
throws IOException {
|
||||
readFully(is, buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks till the required number of bytes have been read from the
|
||||
* input stream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param buffer the buffer to store the bytes into
|
||||
* @param offset the offset to start storing at
|
||||
* @param len the number of bytes to read
|
||||
* @throws EOFException if EOF is reached before all bytes are
|
||||
* read.
|
||||
* @throws IOException is an error occurs while reading
|
||||
*/
|
||||
public static final void readFully(InputStream is,
|
||||
byte[] buffer, int offset, int len)
|
||||
throws IOException {
|
||||
int temp;
|
||||
while (len > 0) {
|
||||
temp = is.read(buffer, offset, len);
|
||||
if (temp == -1)
|
||||
throw new EOFException("Cannot read all "
|
||||
+ len
|
||||
+ " bytes needed to form this token!");
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
|
||||
public static final void debug(String str) {
|
||||
System.err.print(str);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes) {
|
||||
return getHexBytes(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes, int len) {
|
||||
return getHexBytes(bytes, 0, len);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes, int pos, int len) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = pos; i < (pos+len); i++) {
|
||||
int b1 = (bytes[i]>>4) & 0x0f;
|
||||
int b2 = bytes[i] & 0x0f;
|
||||
|
||||
sb.append(Integer.toHexString(b1));
|
||||
sb.append(Integer.toHexString(b2));
|
||||
sb.append(' ');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
366
jdkSrc/jdk8/sun/security/jgss/GSSUtil.java
Normal file
366
jdkSrc/jdk8/sun/security/jgss/GSSUtil.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import com.sun.security.auth.callback.TextCallbackHandler;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.jgss.krb5.Krb5NameElement;
|
||||
import sun.security.jgss.spnego.SpNegoCredElement;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
/**
|
||||
* The GSSUtilImplementation that knows how to work with the internals of
|
||||
* the GSS-API.
|
||||
*/
|
||||
public class GSSUtil {
|
||||
|
||||
public static final Oid GSS_KRB5_MECH_OID =
|
||||
GSSUtil.createOid("1.2.840.113554.1.2.2");
|
||||
public static final Oid GSS_KRB5_MECH_OID2 =
|
||||
GSSUtil.createOid("1.3.5.1.5.2");
|
||||
public static final Oid GSS_KRB5_MECH_OID_MS =
|
||||
GSSUtil.createOid("1.2.840.48018.1.2.2");
|
||||
|
||||
public static final Oid GSS_SPNEGO_MECH_OID =
|
||||
GSSUtil.createOid("1.3.6.1.5.5.2");
|
||||
|
||||
public static final Oid NT_GSS_KRB5_PRINCIPAL =
|
||||
GSSUtil.createOid("1.2.840.113554.1.2.2.1");
|
||||
|
||||
private static final String DEFAULT_HANDLER =
|
||||
"auth.login.defaultCallbackHandler";
|
||||
|
||||
static final boolean DEBUG;
|
||||
static {
|
||||
DEBUG = (AccessController.doPrivileged
|
||||
(new GetBooleanAction("sun.security.jgss.debug"))).
|
||||
booleanValue();
|
||||
}
|
||||
|
||||
static void debug(String message) {
|
||||
if (DEBUG) {
|
||||
assert(message != null);
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this method is only for creating Oid objects with
|
||||
// known to be valid <code>oidStr</code> given it ignores
|
||||
// the GSSException
|
||||
public static Oid createOid(String oidStr) {
|
||||
try {
|
||||
return new Oid(oidStr);
|
||||
} catch (GSSException e) {
|
||||
debug("Ignored invalid OID: " + oidStr);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSpNegoMech(Oid oid) {
|
||||
return (GSS_SPNEGO_MECH_OID.equals(oid));
|
||||
}
|
||||
|
||||
public static boolean isKerberosMech(Oid oid) {
|
||||
return (GSS_KRB5_MECH_OID.equals(oid) ||
|
||||
GSS_KRB5_MECH_OID2.equals(oid) ||
|
||||
GSS_KRB5_MECH_OID_MS.equals(oid));
|
||||
|
||||
}
|
||||
|
||||
public static String getMechStr(Oid oid) {
|
||||
if (isSpNegoMech(oid)) {
|
||||
return "SPNEGO";
|
||||
} else if (isKerberosMech(oid)) {
|
||||
return "Kerberos V5";
|
||||
} else {
|
||||
return oid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: The current impl only works with Sun's impl of
|
||||
* GSSName and GSSCredential since it depends on package
|
||||
* private APIs.
|
||||
*/
|
||||
public static Subject getSubject(GSSName name,
|
||||
GSSCredential creds) {
|
||||
|
||||
HashSet<Object> privCredentials = null;
|
||||
HashSet<Object> pubCredentials = new HashSet<Object>(); // empty Set
|
||||
|
||||
Set<GSSCredentialSpi> gssCredentials = null;
|
||||
|
||||
Set<KerberosPrincipal> krb5Principals =
|
||||
new HashSet<KerberosPrincipal>();
|
||||
|
||||
if (name instanceof GSSNameImpl) {
|
||||
try {
|
||||
GSSNameSpi ne = ((GSSNameImpl) name).getElement
|
||||
(GSS_KRB5_MECH_OID);
|
||||
String krbName = ne.toString();
|
||||
if (ne instanceof Krb5NameElement) {
|
||||
krbName =
|
||||
((Krb5NameElement) ne).getKrb5PrincipalName().getName();
|
||||
}
|
||||
KerberosPrincipal krbPrinc = new KerberosPrincipal(krbName);
|
||||
krb5Principals.add(krbPrinc);
|
||||
} catch (GSSException ge) {
|
||||
debug("Skipped name " + name + " due to " + ge);
|
||||
}
|
||||
}
|
||||
|
||||
if (creds instanceof GSSCredentialImpl) {
|
||||
gssCredentials = ((GSSCredentialImpl) creds).getElements();
|
||||
privCredentials = new HashSet<Object>(gssCredentials.size());
|
||||
populateCredentials(privCredentials, gssCredentials);
|
||||
} else {
|
||||
privCredentials = new HashSet<Object>(); // empty Set
|
||||
}
|
||||
debug("Created Subject with the following");
|
||||
debug("principals=" + krb5Principals);
|
||||
debug("public creds=" + pubCredentials);
|
||||
debug("private creds=" + privCredentials);
|
||||
|
||||
return new Subject(false, krb5Principals, pubCredentials,
|
||||
privCredentials);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the set credentials with elements from gssCredentials. At
|
||||
* the same time, it converts any subclasses of KerberosTicket
|
||||
* into KerberosTicket instances and any subclasses of KerberosKey into
|
||||
* KerberosKey instances. (It is not desirable to expose the customer
|
||||
* to sun.security.jgss.krb5.Krb5InitCredential which extends
|
||||
* KerberosTicket and sun.security.jgss.krb5.Kbr5AcceptCredential which
|
||||
* extends KerberosKey.)
|
||||
*/
|
||||
private static void populateCredentials(Set<Object> credentials,
|
||||
Set<?> gssCredentials) {
|
||||
|
||||
Object cred;
|
||||
|
||||
Iterator<?> elements = gssCredentials.iterator();
|
||||
while (elements.hasNext()) {
|
||||
|
||||
cred = elements.next();
|
||||
|
||||
// Retrieve the internal cred out of SpNegoCredElement
|
||||
if (cred instanceof SpNegoCredElement) {
|
||||
cred = ((SpNegoCredElement) cred).getInternalCred();
|
||||
}
|
||||
|
||||
if (cred instanceof KerberosTicket) {
|
||||
if (!cred.getClass().getName().equals
|
||||
("javax.security.auth.kerberos.KerberosTicket")) {
|
||||
KerberosTicket tempTkt = (KerberosTicket) cred;
|
||||
cred = new KerberosTicket(tempTkt.getEncoded(),
|
||||
tempTkt.getClient(),
|
||||
tempTkt.getServer(),
|
||||
tempTkt.getSessionKey().getEncoded(),
|
||||
tempTkt.getSessionKeyType(),
|
||||
tempTkt.getFlags(),
|
||||
tempTkt.getAuthTime(),
|
||||
tempTkt.getStartTime(),
|
||||
tempTkt.getEndTime(),
|
||||
tempTkt.getRenewTill(),
|
||||
tempTkt.getClientAddresses());
|
||||
}
|
||||
credentials.add(cred);
|
||||
} else if (cred instanceof KerberosKey) {
|
||||
if (!cred.getClass().getName().equals
|
||||
("javax.security.auth.kerberos.KerberosKey")) {
|
||||
KerberosKey tempKey = (KerberosKey) cred;
|
||||
cred = new KerberosKey(tempKey.getPrincipal(),
|
||||
tempKey.getEncoded(),
|
||||
tempKey.getKeyType(),
|
||||
tempKey.getVersionNumber());
|
||||
}
|
||||
credentials.add(cred);
|
||||
} else {
|
||||
// Ignore non-KerberosTicket and non-KerberosKey elements
|
||||
debug("Skipped cred element: " + cred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate using the login module from the specified
|
||||
* configuration entry.
|
||||
*
|
||||
* @param caller the caller of JAAS Login
|
||||
* @param mech the mech to be used
|
||||
* @return the authenticated subject
|
||||
*/
|
||||
public static Subject login(GSSCaller caller, Oid mech) throws LoginException {
|
||||
|
||||
CallbackHandler cb = null;
|
||||
if (caller instanceof HttpCaller) {
|
||||
cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler(
|
||||
((HttpCaller)caller).info());
|
||||
} else {
|
||||
String defaultHandler =
|
||||
java.security.Security.getProperty(DEFAULT_HANDLER);
|
||||
// get the default callback handler
|
||||
if ((defaultHandler != null) && (defaultHandler.length() != 0)) {
|
||||
cb = null;
|
||||
} else {
|
||||
cb = new TextCallbackHandler();
|
||||
}
|
||||
}
|
||||
|
||||
// New instance of LoginConfigImpl must be created for each login,
|
||||
// since the entry name is not passed as the first argument, but
|
||||
// generated with caller and mech inside LoginConfigImpl
|
||||
LoginContext lc = new LoginContext("", null, cb,
|
||||
new LoginConfigImpl(caller, mech));
|
||||
lc.login();
|
||||
return lc.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the application doesn't mind if the mechanism obtains
|
||||
* the required credentials from outside of the current Subject. Our
|
||||
* Kerberos v5 mechanism would do a JAAS login on behalf of the
|
||||
* application if this were the case.
|
||||
*
|
||||
* The application indicates this by explicitly setting the system
|
||||
* property javax.security.auth.useSubjectCredsOnly to false.
|
||||
*/
|
||||
public static boolean useSubjectCredsOnly(GSSCaller caller) {
|
||||
|
||||
String propValue = GetPropertyAction.privilegedGetProperty(
|
||||
"javax.security.auth.useSubjectCredsOnly");
|
||||
|
||||
// Invalid values should be ignored and the default assumed.
|
||||
if (caller instanceof HttpCaller) {
|
||||
// Default for HTTP/SPNEGO is false.
|
||||
return "true".equalsIgnoreCase(propValue);
|
||||
} else {
|
||||
// Default for JGSS is true.
|
||||
return !("false".equalsIgnoreCase(propValue));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the SPNEGO interoperability mode with Microsoft;
|
||||
* by default it is set to true.
|
||||
*
|
||||
* To disable it, the application indicates this by explicitly setting
|
||||
* the system property sun.security.spnego.interop to false.
|
||||
*/
|
||||
public static boolean useMSInterop() {
|
||||
/*
|
||||
* Don't use GetBooleanAction because the default value in the JRE
|
||||
* (when this is unset) has to treated as true.
|
||||
*/
|
||||
String propValue = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.security.spnego.msinterop",
|
||||
"true"));
|
||||
/*
|
||||
* This property has to be explicitly set to "false". Invalid
|
||||
* values should be ignored and the default "true" assumed.
|
||||
*/
|
||||
return (!propValue.equalsIgnoreCase("false"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the private credentials of current Subject with the
|
||||
* specified criteria and returns the matching GSSCredentialSpi
|
||||
* object out of Sun's impl of GSSCredential. Returns null if
|
||||
* no Subject present or a Vector which contains 0 or more
|
||||
* matching GSSCredentialSpi objects.
|
||||
*/
|
||||
public static <T extends GSSCredentialSpi> Vector<T>
|
||||
searchSubject(final GSSNameSpi name,
|
||||
final Oid mech,
|
||||
final boolean initiate,
|
||||
final Class<? extends T> credCls) {
|
||||
debug("Search Subject for " + getMechStr(mech) +
|
||||
(initiate? " INIT" : " ACCEPT") + " cred (" +
|
||||
(name == null? "<<DEF>>" : name.toString()) + ", " +
|
||||
credCls.getName() + ")");
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
try {
|
||||
Vector<T> creds =
|
||||
AccessController.doPrivileged
|
||||
(new PrivilegedExceptionAction<Vector<T>>() {
|
||||
public Vector<T> run() throws Exception {
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
Vector<T> result = null;
|
||||
if (accSubj != null) {
|
||||
result = new Vector<T>();
|
||||
Iterator<GSSCredentialImpl> iterator =
|
||||
accSubj.getPrivateCredentials
|
||||
(GSSCredentialImpl.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
GSSCredentialImpl cred = iterator.next();
|
||||
debug("...Found cred" + cred);
|
||||
try {
|
||||
GSSCredentialSpi ce =
|
||||
cred.getElement(mech, initiate);
|
||||
debug("......Found element: " + ce);
|
||||
if (ce.getClass().equals(credCls) &&
|
||||
(name == null ||
|
||||
name.equals((Object) ce.getName()))) {
|
||||
result.add(credCls.cast(ce));
|
||||
} else {
|
||||
debug("......Discard element");
|
||||
}
|
||||
} catch (GSSException ge) {
|
||||
debug("...Discard cred (" + ge + ")");
|
||||
}
|
||||
}
|
||||
} else debug("No Subject");
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return creds;
|
||||
} catch (PrivilegedActionException pae) {
|
||||
debug("Unexpected exception when searching Subject:");
|
||||
if (DEBUG) pae.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
jdkSrc/jdk8/sun/security/jgss/HttpCaller.java
Normal file
46
jdkSrc/jdk8/sun/security/jgss/HttpCaller.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import sun.net.www.protocol.http.HttpCallerInfo;
|
||||
|
||||
/**
|
||||
* A special kind of GSSCaller, which origins from HTTP/Negotiate and contains
|
||||
* info about what triggers the JGSS calls.
|
||||
*/
|
||||
public class HttpCaller extends GSSCaller {
|
||||
final private HttpCallerInfo hci;
|
||||
|
||||
public HttpCaller(HttpCallerInfo hci) {
|
||||
super("HTTP_CLIENT");
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
public HttpCallerInfo info() {
|
||||
return hci;
|
||||
}
|
||||
}
|
||||
|
||||
213
jdkSrc/jdk8/sun/security/jgss/LoginConfigImpl.java
Normal file
213
jdkSrc/jdk8/sun/security/jgss/LoginConfigImpl.java
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import java.util.HashMap;
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import org.ietf.jgss.Oid;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* A Configuration implementation especially designed for JGSS.
|
||||
*
|
||||
* @author weijun.wang
|
||||
* @since 1.6
|
||||
*/
|
||||
public class LoginConfigImpl extends Configuration {
|
||||
|
||||
private final Configuration config;
|
||||
private final GSSCaller caller;
|
||||
private final String mechName;
|
||||
private static final sun.security.util.Debug debug =
|
||||
sun.security.util.Debug.getInstance("gssloginconfig", "\t[GSS LoginConfigImpl]");
|
||||
|
||||
public static final boolean HTTP_USE_GLOBAL_CREDS;
|
||||
|
||||
static {
|
||||
String prop = GetPropertyAction
|
||||
.privilegedGetProperty("http.use.global.creds");
|
||||
//HTTP_USE_GLOBAL_CREDS = "true".equalsIgnoreCase(prop); // default false
|
||||
HTTP_USE_GLOBAL_CREDS = !"false".equalsIgnoreCase(prop); // default true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A new instance of LoginConfigImpl must be created for each login request
|
||||
* since it's only used by a single (caller, mech) pair
|
||||
* @param caller defined in GSSUtil as CALLER_XXX final fields
|
||||
* @param mech defined in GSSUtil as XXX_MECH_OID final fields
|
||||
*/
|
||||
public LoginConfigImpl(GSSCaller caller, Oid mech) {
|
||||
|
||||
this.caller = caller;
|
||||
|
||||
if (mech.equals(GSSUtil.GSS_KRB5_MECH_OID)) {
|
||||
mechName = "krb5";
|
||||
} else {
|
||||
throw new IllegalArgumentException(mech.toString() + " not supported");
|
||||
}
|
||||
config = java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction <Configuration> () {
|
||||
public Configuration run() {
|
||||
return Configuration.getConfiguration();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Almost useless, since the (caller, mech) is already passed
|
||||
* into constructor. The only use will be detecting OTHER which
|
||||
* is called in LoginContext
|
||||
*/
|
||||
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
|
||||
|
||||
AppConfigurationEntry[] entries = null;
|
||||
|
||||
// This is the second call from LoginContext, which we will just ignore
|
||||
if ("OTHER".equalsIgnoreCase(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] alts = null;
|
||||
|
||||
// Compatibility:
|
||||
// For the 4 old callers, old entry names will be used if the new
|
||||
// entry name is not provided.
|
||||
|
||||
if ("krb5".equals(mechName)) {
|
||||
if (caller == GSSCaller.CALLER_INITIATE) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
"com.sun.security.jgss.initiate",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_ACCEPT) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.accept",
|
||||
"com.sun.security.jgss.accept",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_SSL_CLIENT) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
"com.sun.net.ssl.client",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_SSL_SERVER) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.accept",
|
||||
"com.sun.net.ssl.server",
|
||||
};
|
||||
} else if (caller instanceof HttpCaller) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_UNKNOWN) {
|
||||
throw new AssertionError("caller not defined");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(mechName + " not supported");
|
||||
// No other mech at the moment, maybe --
|
||||
/*
|
||||
switch (caller) {
|
||||
case GSSUtil.CALLER_INITIATE:
|
||||
case GSSUtil.CALLER_SSL_CLIENT:
|
||||
case GSSUtil.CALLER_HTTP_NEGOTIATE:
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss." + mechName + ".initiate",
|
||||
};
|
||||
break;
|
||||
case GSSUtil.CALLER_ACCEPT:
|
||||
case GSSUtil.CALLER_SSL_SERVER:
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss." + mechName + ".accept",
|
||||
};
|
||||
break;
|
||||
case GSSUtil.CALLER_UNKNOWN:
|
||||
// should never use
|
||||
throw new AssertionError("caller cannot be unknown");
|
||||
default:
|
||||
throw new AssertionError("caller not defined");
|
||||
}
|
||||
*/
|
||||
}
|
||||
for (String alt: alts) {
|
||||
entries = config.getAppConfigurationEntry(alt);
|
||||
if (debug != null) {
|
||||
debug.println("Trying " + alt +
|
||||
((entries == null)?": does not exist.":": Found!"));
|
||||
}
|
||||
if (entries != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entries == null) {
|
||||
if (debug != null) {
|
||||
debug.println("Cannot read JGSS entry, use default values instead.");
|
||||
}
|
||||
entries = getDefaultConfigurationEntry();
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value for a caller-mech pair when no entry is defined in
|
||||
* the system-wide Configuration object.
|
||||
*/
|
||||
private AppConfigurationEntry[] getDefaultConfigurationEntry() {
|
||||
HashMap <String, String> options = new HashMap <String, String> (2);
|
||||
|
||||
if (mechName == null || mechName.equals("krb5")) {
|
||||
if (isServerSide(caller)) {
|
||||
// Assuming the keytab file can be found through
|
||||
// krb5 config file or under user home directory
|
||||
options.put("useKeyTab", "true");
|
||||
options.put("storeKey", "true");
|
||||
options.put("doNotPrompt", "true");
|
||||
options.put("principal", "*");
|
||||
options.put("isInitiator", "false");
|
||||
} else {
|
||||
if (caller instanceof HttpCaller && !HTTP_USE_GLOBAL_CREDS) {
|
||||
options.put("useTicketCache", "false");
|
||||
} else {
|
||||
options.put("useTicketCache", "true");
|
||||
}
|
||||
options.put("doNotPrompt", "false");
|
||||
}
|
||||
return new AppConfigurationEntry[] {
|
||||
new AppConfigurationEntry(
|
||||
"com.sun.security.auth.module.Krb5LoginModule",
|
||||
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
|
||||
options)
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isServerSide (GSSCaller caller) {
|
||||
return GSSCaller.CALLER_ACCEPT == caller ||
|
||||
GSSCaller.CALLER_SSL_SERVER == caller;
|
||||
}
|
||||
}
|
||||
547
jdkSrc/jdk8/sun/security/jgss/ProviderList.java
Normal file
547
jdkSrc/jdk8/sun/security/jgss/ProviderList.java
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.jgss.wrapper.NativeGSSFactory;
|
||||
import sun.security.jgss.wrapper.SunNativeProvider;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class stores the list of providers that this
|
||||
* GSS-Implementation is configured to use. The GSSManagerImpl class
|
||||
* queries this class whenever it needs a mechanism's factory.<p>
|
||||
*
|
||||
* This class stores an ordered list of pairs of the form
|
||||
* {@code <provider, oid>}. When it attempts to instantiate a mechanism
|
||||
* defined by oid o, it steps through the list looking for an entry
|
||||
* with oid=o, or with oid=null. (An entry with oid=null matches all
|
||||
* mechanisms.) When it finds such an entry, the corresponding
|
||||
* provider is approached for the mechanism's factory class.
|
||||
* At instantiation time this list in initialized to contain those
|
||||
* system wide providers that contain a property of the form
|
||||
* "GssApiMechanism.x.y.z..." where "x.y.z..." is a numeric object
|
||||
* identifier with numbers x, y, z, etc. Such a property is defined
|
||||
* to map to that provider's implementation of the MechanismFactory
|
||||
* interface for the mechanism x.y.z...
|
||||
* As and when a MechanismFactory is instantiated, it is
|
||||
* cached for future use. <p>
|
||||
*
|
||||
* An application can cause more providers to be added by means of
|
||||
* the addProviderAtFront and addProviderAtEnd methods on
|
||||
* GSSManager which get delegated to this class. The
|
||||
* addProviderAtFront method can also cause a change in the ordering
|
||||
* of the providers without adding any new providers, by causing a
|
||||
* provider to move up in a list. The method addProviderAtEnd can
|
||||
* only add providers at the end of the list if they are not already
|
||||
* in the list. The rationale is that an application will call
|
||||
* addProviderAtFront when it wants a provider to be used in
|
||||
* preference over the default ones. And it will call
|
||||
* addProviderAtEnd when it wants a provider to be used in case
|
||||
* the system ones don't suffice.<p>
|
||||
*
|
||||
* If a mechanism's factory is being obtained from a provider as a
|
||||
* result of encountering a entryof the form {@code <provider, oid>} where
|
||||
* oid is non-null, then the assumption is that the application added
|
||||
* this entry and it wants this mechanism to be obtained from this
|
||||
* provider. Thus is the provider does not actually contain the
|
||||
* requested mechanism, an exception will be thrown. However, if the
|
||||
* entry were of the form {@code <provider, null>}, then it is viewed more
|
||||
* liberally and is simply skipped over if the provider does not claim to
|
||||
* support the requested mechanism.
|
||||
*/
|
||||
|
||||
public final class ProviderList {
|
||||
|
||||
private static final String PROV_PROP_PREFIX = "GssApiMechanism.";
|
||||
private static final int PROV_PROP_PREFIX_LEN =
|
||||
PROV_PROP_PREFIX.length();
|
||||
|
||||
private static final String SPI_MECH_FACTORY_TYPE
|
||||
= "sun.security.jgss.spi.MechanismFactory";
|
||||
|
||||
// Undocumented property?
|
||||
private static final String DEFAULT_MECH_PROP =
|
||||
"sun.security.jgss.mechanism";
|
||||
|
||||
public static final Oid DEFAULT_MECH_OID;
|
||||
|
||||
static {
|
||||
/*
|
||||
* Set the default mechanism. Kerberos v5 is the default
|
||||
* mechanism unless it is overridden by a system property.
|
||||
* with a valid OID value
|
||||
*/
|
||||
Oid defOid = null;
|
||||
String defaultOidStr = AccessController.doPrivileged
|
||||
(new GetPropertyAction(DEFAULT_MECH_PROP));
|
||||
if (defaultOidStr != null) {
|
||||
defOid = GSSUtil.createOid(defaultOidStr);
|
||||
}
|
||||
DEFAULT_MECH_OID =
|
||||
(defOid == null ? GSSUtil.GSS_KRB5_MECH_OID : defOid);
|
||||
}
|
||||
|
||||
private ArrayList<PreferencesEntry> preferences =
|
||||
new ArrayList<PreferencesEntry>(5);
|
||||
private HashMap<PreferencesEntry, MechanismFactory> factories =
|
||||
new HashMap<PreferencesEntry, MechanismFactory>(5);
|
||||
private HashSet<Oid> mechs = new HashSet<Oid>(5);
|
||||
|
||||
final private GSSCaller caller;
|
||||
|
||||
public ProviderList(GSSCaller caller, boolean useNative) {
|
||||
this.caller = caller;
|
||||
Provider[] provList;
|
||||
if (useNative) {
|
||||
provList = new Provider[1];
|
||||
provList[0] = new SunNativeProvider();
|
||||
} else {
|
||||
provList = Security.getProviders();
|
||||
}
|
||||
|
||||
for (int i = 0; i < provList.length; i++) {
|
||||
Provider prov = provList[i];
|
||||
try {
|
||||
addProviderAtEnd(prov, null);
|
||||
} catch (GSSException ge) {
|
||||
// Move on to the next provider
|
||||
GSSUtil.debug("Error in adding provider " +
|
||||
prov.getName() + ": " + ge);
|
||||
}
|
||||
} // End of for loop
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given provider property represents a GSS-API
|
||||
* Oid to MechanismFactory mapping.
|
||||
* @return true if this is a GSS-API property, false otherwise.
|
||||
*/
|
||||
private boolean isMechFactoryProperty(String prop) {
|
||||
return (prop.startsWith(PROV_PROP_PREFIX) ||
|
||||
prop.regionMatches(true, 0, // Try ignoring case
|
||||
PROV_PROP_PREFIX, 0,
|
||||
PROV_PROP_PREFIX_LEN));
|
||||
}
|
||||
|
||||
private Oid getOidFromMechFactoryProperty(String prop)
|
||||
throws GSSException {
|
||||
|
||||
String oidPart = prop.substring(PROV_PROP_PREFIX_LEN);
|
||||
return new Oid(oidPart);
|
||||
}
|
||||
|
||||
// So the existing code do not have to be changed
|
||||
synchronized public MechanismFactory getMechFactory(Oid mechOid)
|
||||
throws GSSException {
|
||||
if (mechOid == null) mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
return getMechFactory(mechOid, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a MechanismFactory for a given mechanism. If the
|
||||
* specified provider is not null, then the impl from the
|
||||
* provider is used. Otherwise, the most preferred impl based
|
||||
* on the configured preferences is used.
|
||||
* @param mechOid the oid of the desired mechanism
|
||||
* @return a MechanismFactory for the desired mechanism.
|
||||
* @throws GSSException when the specified provider does not
|
||||
* support the desired mechanism, or when no provider supports
|
||||
* the desired mechanism.
|
||||
*/
|
||||
synchronized public MechanismFactory getMechFactory(Oid mechOid,
|
||||
Provider p)
|
||||
throws GSSException {
|
||||
|
||||
if (mechOid == null) mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
if (p == null) {
|
||||
// Iterate thru all preferences to find right provider
|
||||
String className;
|
||||
PreferencesEntry entry;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
entry = list.next();
|
||||
if (entry.impliesMechanism(mechOid)) {
|
||||
MechanismFactory retVal = getMechFactory(entry, mechOid);
|
||||
if (retVal != null) return retVal;
|
||||
}
|
||||
} // end of while loop
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mechOid);
|
||||
} else {
|
||||
// Use the impl from the specified provider; return null if the
|
||||
// the mech is unsupported by the specified provider.
|
||||
PreferencesEntry entry = new PreferencesEntry(p, mechOid);
|
||||
return getMechFactory(entry, mechOid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine that uses a preferences entry to obtain an
|
||||
* implementation of a MechanismFactory from it.
|
||||
* @param e the preferences entry that contains the provider and
|
||||
* either a null of an explicit oid that matched the oid of the
|
||||
* desired mechanism.
|
||||
* @param mechOid the oid of the desired mechanism
|
||||
* @throws GSSException If the application explicitly requested
|
||||
* this entry's provider to be used for the desired mechanism but
|
||||
* some problem is encountered
|
||||
*/
|
||||
private MechanismFactory getMechFactory(PreferencesEntry e, Oid mechOid)
|
||||
throws GSSException {
|
||||
Provider p = e.getProvider();
|
||||
|
||||
/*
|
||||
* See if a MechanismFactory was previously instantiated for
|
||||
* this provider and mechanism combination.
|
||||
*/
|
||||
PreferencesEntry searchEntry = new PreferencesEntry(p, mechOid);
|
||||
MechanismFactory retVal = factories.get(searchEntry);
|
||||
if (retVal == null) {
|
||||
/*
|
||||
* Apparently not. Now try to instantiate this class from
|
||||
* the provider.
|
||||
*/
|
||||
String prop = PROV_PROP_PREFIX + mechOid.toString();
|
||||
String className = p.getProperty(prop);
|
||||
if (className != null) {
|
||||
retVal = getMechFactoryImpl(p, className, mechOid, caller);
|
||||
factories.put(searchEntry, retVal);
|
||||
} else {
|
||||
/*
|
||||
* This provider does not support this mechanism.
|
||||
* If the application explicitly requested that
|
||||
* this provider be used for this mechanism, then
|
||||
* throw an exception
|
||||
*/
|
||||
if (e.getOid() != null) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName() +
|
||||
" does not support mechanism " + mechOid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain a MechanismFactory implementation
|
||||
* from the same class loader as the provider of this
|
||||
* implementation.
|
||||
* @param p the provider whose classloader must be used for
|
||||
* instantiating the desired MechanismFactory
|
||||
* @ param className the name of the MechanismFactory class
|
||||
* @throws GSSException If some error occurs when trying to
|
||||
* instantiate this MechanismFactory.
|
||||
*/
|
||||
private static MechanismFactory getMechFactoryImpl(Provider p,
|
||||
String className,
|
||||
Oid mechOid,
|
||||
GSSCaller caller)
|
||||
throws GSSException {
|
||||
|
||||
try {
|
||||
Class<?> baseClass = Class.forName(SPI_MECH_FACTORY_TYPE);
|
||||
|
||||
/*
|
||||
* Load the implementation class with the same class loader
|
||||
* that was used to load the provider.
|
||||
* In order to get the class loader of a class, the
|
||||
* caller's class loader must be the same as or an ancestor of
|
||||
* the class loader being returned. Otherwise, the caller must
|
||||
* have "getClassLoader" permission, or a SecurityException
|
||||
* will be thrown.
|
||||
*/
|
||||
|
||||
ClassLoader cl = p.getClass().getClassLoader();
|
||||
Class<?> implClass;
|
||||
if (cl != null) {
|
||||
implClass = cl.loadClass(className);
|
||||
} else {
|
||||
implClass = Class.forName(className);
|
||||
}
|
||||
|
||||
if (baseClass.isAssignableFrom(implClass)) {
|
||||
|
||||
java.lang.reflect.Constructor<?> c =
|
||||
implClass.getConstructor(GSSCaller.class);
|
||||
MechanismFactory mf = (MechanismFactory) (c.newInstance(caller));
|
||||
|
||||
if (mf instanceof NativeGSSFactory) {
|
||||
((NativeGSSFactory) mf).setMech(mechOid);
|
||||
}
|
||||
return mf;
|
||||
} else {
|
||||
throw createGSSException(p, className, "is not a " +
|
||||
SPI_MECH_FACTORY_TYPE, null);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (InstantiationException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (SecurityException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Only used by getMechFactoryImpl
|
||||
private static GSSException createGSSException(Provider p,
|
||||
String className,
|
||||
String trailingMsg,
|
||||
Exception cause) {
|
||||
String errClassInfo = className + " configured by " +
|
||||
p.getName() + " for GSS-API Mechanism Factory ";
|
||||
return new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
errClassInfo + trailingMsg,
|
||||
cause);
|
||||
}
|
||||
|
||||
public Oid[] getMechs() {
|
||||
return mechs.toArray(new Oid[] {});
|
||||
}
|
||||
|
||||
synchronized public void addProviderAtFront(Provider p, Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
PreferencesEntry newEntry = new PreferencesEntry(p, mechOid);
|
||||
PreferencesEntry oldEntry;
|
||||
boolean foundSomeMech;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
oldEntry = list.next();
|
||||
if (newEntry.implies(oldEntry))
|
||||
list.remove();
|
||||
}
|
||||
|
||||
if (mechOid == null) {
|
||||
foundSomeMech = addAllMechsFromProvider(p);
|
||||
} else {
|
||||
String oidStr = mechOid.toString();
|
||||
if (p.getProperty(PROV_PROP_PREFIX + oidStr) == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName()
|
||||
+ " does not support "
|
||||
+ oidStr);
|
||||
mechs.add(mechOid);
|
||||
foundSomeMech = true;
|
||||
}
|
||||
|
||||
if (foundSomeMech) {
|
||||
preferences.add(0, newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void addProviderAtEnd(Provider p, Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
PreferencesEntry newEntry = new PreferencesEntry(p, mechOid);
|
||||
PreferencesEntry oldEntry;
|
||||
boolean foundSomeMech;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
oldEntry = list.next();
|
||||
if (oldEntry.implies(newEntry))
|
||||
return;
|
||||
}
|
||||
|
||||
// System.out.println("addProviderAtEnd: No it is not redundant");
|
||||
|
||||
if (mechOid == null)
|
||||
foundSomeMech = addAllMechsFromProvider(p);
|
||||
else {
|
||||
String oidStr = mechOid.toString();
|
||||
if (p.getProperty(PROV_PROP_PREFIX + oidStr) == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName()
|
||||
+ " does not support "
|
||||
+ oidStr);
|
||||
mechs.add(mechOid);
|
||||
foundSomeMech = true;
|
||||
}
|
||||
|
||||
if (foundSomeMech) {
|
||||
preferences.add(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to go through all properties contined in a
|
||||
* provider and add its mechanisms to the list of supported
|
||||
* mechanisms. If no default mechanism has been assinged so far,
|
||||
* it sets the default MechanismFactory and Oid as well.
|
||||
* @param p the provider to query
|
||||
* @return true if there is at least one mechanism that this
|
||||
* provider contributed, false otherwise
|
||||
*/
|
||||
private boolean addAllMechsFromProvider(Provider p) {
|
||||
|
||||
String prop;
|
||||
boolean retVal = false;
|
||||
|
||||
// Get all props for this provider
|
||||
Enumeration<Object> props = p.keys();
|
||||
|
||||
// See if there are any GSS prop's
|
||||
while (props.hasMoreElements()) {
|
||||
prop = (String) props.nextElement();
|
||||
if (isMechFactoryProperty(prop)) {
|
||||
// Ok! This is a GSS provider!
|
||||
try {
|
||||
Oid mechOid = getOidFromMechFactoryProperty(prop);
|
||||
mechs.add(mechOid);
|
||||
retVal = true;
|
||||
} catch (GSSException e) {
|
||||
// Skip to next property
|
||||
GSSUtil.debug("Ignore the invalid property " +
|
||||
prop + " from provider " + p.getName());
|
||||
}
|
||||
} // Processed GSS property
|
||||
} // while loop
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a provider and a mechanism oid indicating that the
|
||||
* provider should be used for the mechanism. If the mechanism
|
||||
* Oid is null, then it indicates that this preference holds for
|
||||
* any mechanism.<p>
|
||||
*
|
||||
* The ProviderList maintains an ordered list of
|
||||
* PreferencesEntry's and iterates thru them as it tries to
|
||||
* instantiate MechanismFactory's.
|
||||
*/
|
||||
private static final class PreferencesEntry {
|
||||
private Provider p;
|
||||
private Oid oid;
|
||||
PreferencesEntry(Provider p, Oid oid) {
|
||||
this.p = p;
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof PreferencesEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PreferencesEntry that = (PreferencesEntry)other;
|
||||
if (this.p.getName().equals(that.p.getName())) {
|
||||
if (this.oid != null && that.oid != null) {
|
||||
return this.oid.equals(that.oid);
|
||||
} else {
|
||||
return (this.oid == null && that.oid == null);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
|
||||
result = 37 * result + p.getName().hashCode();
|
||||
if (oid != null) {
|
||||
result = 37 * result + oid.hashCode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a preference implies another. A preference
|
||||
* implies another if the latter is subsumed by the
|
||||
* former. e.g., <Provider1, null> implies <Provider1, OidX>
|
||||
* because the null in the former indicates that it should
|
||||
* be used for all mechanisms.
|
||||
*/
|
||||
boolean implies(Object other) {
|
||||
|
||||
if (other instanceof PreferencesEntry) {
|
||||
PreferencesEntry temp = (PreferencesEntry) other;
|
||||
return (equals(temp) ||
|
||||
p.getName().equals(temp.p.getName()) &&
|
||||
oid == null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Provider getProvider() {
|
||||
return p;
|
||||
}
|
||||
|
||||
Oid getOid() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this entry is applicable to the desired
|
||||
* mechanism. The entry is applicable to the desired mech if
|
||||
* it contains the same oid or if it contains a null oid
|
||||
* indicating that it is applicable to all mechs.
|
||||
* @param mechOid the desired mechanism
|
||||
* @return true if the provider in this entry should be
|
||||
* queried for this mechanism.
|
||||
*/
|
||||
boolean impliesMechanism(Oid oid) {
|
||||
return (this.oid == null || this.oid.equals(oid));
|
||||
}
|
||||
|
||||
// For debugging
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("<");
|
||||
buf.append(p.getName());
|
||||
buf.append(", ");
|
||||
buf.append(oid);
|
||||
buf.append(">");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
jdkSrc/jdk8/sun/security/jgss/SunProvider.java
Normal file
82
jdkSrc/jdk8/sun/security/jgss/SunProvider.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
|
||||
/**
|
||||
* Defines the Sun JGSS provider.
|
||||
* Will merger this with the Sun security provider
|
||||
* sun.security.provider.Sun when the JGSS src is merged with the JDK
|
||||
* src.
|
||||
*
|
||||
* Mechanisms supported are:
|
||||
*
|
||||
* - Kerberos v5 as defined in RFC 1964.
|
||||
* Oid is 1.2.840.113554.1.2.2
|
||||
*
|
||||
* - SPNEGO as defined in RFC 2478
|
||||
* Oid is 1.3.6.1.5.5.2
|
||||
*
|
||||
* [Dummy mechanism is no longer compiled:
|
||||
* - Dummy mechanism. This is primarily useful to test a multi-mech
|
||||
* environment.
|
||||
* Oid is 1.3.6.1.4.1.42.2.26.1.2]
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public final class SunProvider extends Provider {
|
||||
|
||||
private static final long serialVersionUID = -238911724858694198L;
|
||||
|
||||
private static final String INFO = "Sun " +
|
||||
"(Kerberos v5, SPNEGO)";
|
||||
// "(Kerberos v5, Dummy GSS-API Mechanism)";
|
||||
|
||||
public static final SunProvider INSTANCE = new SunProvider();
|
||||
|
||||
public SunProvider() {
|
||||
/* We are the Sun JGSS provider */
|
||||
super("SunJGSS", 1.8d, INFO);
|
||||
|
||||
AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
put("GssApiMechanism.1.2.840.113554.1.2.2",
|
||||
"sun.security.jgss.krb5.Krb5MechFactory");
|
||||
put("GssApiMechanism.1.3.6.1.5.5.2",
|
||||
"sun.security.jgss.spnego.SpNegoMechFactory");
|
||||
/*
|
||||
put("GssApiMechanism.1.3.6.1.4.1.42.2.26.1.2",
|
||||
"sun.security.jgss.dummy.DummyMechFactory");
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
419
jdkSrc/jdk8/sun/security/jgss/TokenTracker.java
Normal file
419
jdkSrc/jdk8/sun/security/jgss/TokenTracker.java
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss;
|
||||
|
||||
import org.ietf.jgss.MessageProp;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* A utility class that implements a number list that keeps track of which
|
||||
* tokens have arrived by storing their token numbers in the list. It helps
|
||||
* detect old tokens, out of sequence tokens, and duplicate tokens.
|
||||
*
|
||||
* Each element of the list is an interval [a, b]. Its existence in the
|
||||
* list implies that all token numbers in the range a, a+1, ..., b-1, b
|
||||
* have arrived. Gaps in arrived token numbers are represented by the
|
||||
* numbers that fall in between two elements of the list. eg. {[a,b],
|
||||
* [c,d]} indicates that the token numbers b+1, ..., c-1 have not arrived
|
||||
* yet.
|
||||
*
|
||||
* The maximum number of intervals that we keep track of is
|
||||
* MAX_INTERVALS. Thus if there are too many gaps, then some of the older
|
||||
* sequence numbers are deleted from the list. The earliest sequence number
|
||||
* that exists in the list is the windowStart. The next expected sequence
|
||||
* number, or expectedNumber, is one greater than the latest sequence
|
||||
* number in the list.
|
||||
*
|
||||
* The list keeps track the first token number that should have arrived
|
||||
* (initNumber) so that it is able to detect if certain numbers occur after
|
||||
* the first valid token number but before windowStart. That would happen
|
||||
* if the number of elements (intervals) exceeds MAX_INTERVALS and some
|
||||
* initial elements had to be deleted.
|
||||
*
|
||||
* The working of the list is optimized for the normal case where the
|
||||
* tokens arrive in sequence.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
public class TokenTracker {
|
||||
|
||||
static final int MAX_INTERVALS = 5;
|
||||
|
||||
private int initNumber;
|
||||
private int windowStart;
|
||||
private int expectedNumber;
|
||||
|
||||
private int windowStartIndex = 0;
|
||||
|
||||
private LinkedList<Entry> list = new LinkedList<Entry>();
|
||||
|
||||
public TokenTracker(int initNumber) {
|
||||
|
||||
this.initNumber = initNumber;
|
||||
this.windowStart = initNumber;
|
||||
this.expectedNumber = initNumber;
|
||||
|
||||
// Make an entry with one less than the expected first token
|
||||
Entry entry = new Entry(initNumber-1);
|
||||
|
||||
list.add(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for the entry into which this number will fit. If
|
||||
* there is none, it returns the index of the last interval
|
||||
* which precedes this number. It returns -1 if the number needs to be
|
||||
* a in a new interval ahead of the whole list.
|
||||
*/
|
||||
private int getIntervalIndex(int number) {
|
||||
Entry entry = null;
|
||||
int i;
|
||||
// Start from the rear to optimize for the normal case
|
||||
for (i = list.size() - 1; i >= 0; i--) {
|
||||
entry = list.get(i);
|
||||
if (entry.compareTo(number) <= 0)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sequencing and replay information for the given token
|
||||
* number.
|
||||
*
|
||||
* The following represents the number line with positions of
|
||||
* initNumber, windowStart, expectedNumber marked on it. Regions in
|
||||
* between them show the different sequencing and replay state
|
||||
* possibilites for tokens that fall in there.
|
||||
*
|
||||
* (1) windowStart
|
||||
* initNumber expectedNumber
|
||||
* | |
|
||||
* ---|---------------------------|---
|
||||
* GAP | DUP/UNSEQ | GAP
|
||||
*
|
||||
*
|
||||
* (2) initNumber windowStart expectedNumber
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* GAP | OLD | DUP/UNSEQ | GAP
|
||||
*
|
||||
*
|
||||
* (3) windowStart
|
||||
* expectedNumber initNumber
|
||||
* | |
|
||||
* ---|---------------------------|---
|
||||
* DUP/UNSEQ | GAP | DUP/UNSEQ
|
||||
*
|
||||
*
|
||||
* (4) expectedNumber initNumber windowStart
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* DUP/UNSEQ | GAP | OLD | DUP/UNSEQ
|
||||
*
|
||||
*
|
||||
*
|
||||
* (5) windowStart expectedNumber initNumber
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* OLD | DUP/UNSEQ | GAP | OLD
|
||||
*
|
||||
*
|
||||
*
|
||||
* (This analysis leaves out the possibility that expectedNumber passes
|
||||
* initNumber after wrapping around. That may be added later.)
|
||||
*/
|
||||
synchronized public final void getProps(int number, MessageProp prop) {
|
||||
|
||||
boolean gap = false;
|
||||
boolean old = false;
|
||||
boolean unsequenced = false;
|
||||
boolean duplicate = false;
|
||||
|
||||
// System.out.println("\n\n==========");
|
||||
// System.out.println("TokenTracker.getProps(): number=" + number);
|
||||
// System.out.println(toString());
|
||||
|
||||
int pos = getIntervalIndex(number);
|
||||
Entry entry = null;
|
||||
if (pos != -1)
|
||||
entry = list.get(pos);
|
||||
|
||||
// Optimize for the expected case:
|
||||
|
||||
if (number == expectedNumber) {
|
||||
expectedNumber++;
|
||||
} else {
|
||||
|
||||
// Next trivial case is to check for duplicate
|
||||
if (entry != null && entry.contains(number))
|
||||
duplicate = true;
|
||||
else {
|
||||
|
||||
if (expectedNumber >= initNumber) {
|
||||
|
||||
// Cases (1) and (2)
|
||||
|
||||
if (number > expectedNumber) {
|
||||
gap = true;
|
||||
} else if (number >= windowStart) {
|
||||
unsequenced = true;
|
||||
} else if (number >= initNumber) {
|
||||
old = true;
|
||||
} else {
|
||||
gap = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
// Cases (3), (4) and (5)
|
||||
|
||||
if (number > expectedNumber) {
|
||||
if (number < initNumber) {
|
||||
gap = true;
|
||||
} else if (windowStart >= initNumber) {
|
||||
if (number >= windowStart) {
|
||||
unsequenced = true;
|
||||
} else
|
||||
old = true;
|
||||
} else {
|
||||
old = true;
|
||||
}
|
||||
} else if (windowStart > expectedNumber) {
|
||||
unsequenced = true;
|
||||
} else if (number < windowStart) {
|
||||
old = true;
|
||||
} else
|
||||
unsequenced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicate && !old)
|
||||
add(number, pos);
|
||||
|
||||
if (gap)
|
||||
expectedNumber = number+1;
|
||||
|
||||
prop.setSupplementaryStates(duplicate, old, unsequenced, gap,
|
||||
0, null);
|
||||
|
||||
// System.out.println("Leaving with state:");
|
||||
// System.out.println(toString());
|
||||
// System.out.println("==========\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the number to the list just after the entry that is currently
|
||||
* at position prevEntryPos. If prevEntryPos is -1, then the number
|
||||
* will begin a new interval at the front of the list.
|
||||
*/
|
||||
private void add(int number, int prevEntryPos) {
|
||||
|
||||
Entry entry;
|
||||
Entry entryBefore = null;
|
||||
Entry entryAfter = null;
|
||||
|
||||
boolean appended = false;
|
||||
boolean prepended = false;
|
||||
|
||||
if (prevEntryPos != -1) {
|
||||
entryBefore = list.get(prevEntryPos);
|
||||
|
||||
// Can this number simply be added to the previous interval?
|
||||
if (number == (entryBefore.getEnd() + 1)) {
|
||||
entryBefore.setEnd(number);
|
||||
appended = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the interval that follows this number
|
||||
|
||||
int nextEntryPos = prevEntryPos + 1;
|
||||
if ((nextEntryPos) < list.size()) {
|
||||
entryAfter = list.get(nextEntryPos);
|
||||
|
||||
// Can this number simply be added to the next interval?
|
||||
if (number == (entryAfter.getStart() - 1)) {
|
||||
if (!appended) {
|
||||
entryAfter.setStart(number);
|
||||
} else {
|
||||
// Merge the two entries
|
||||
entryAfter.setStart(entryBefore.getStart());
|
||||
list.remove(prevEntryPos);
|
||||
// Index of any entry following this gets decremented
|
||||
if (windowStartIndex > prevEntryPos)
|
||||
windowStartIndex--;
|
||||
}
|
||||
prepended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (prepended || appended)
|
||||
return;
|
||||
|
||||
/*
|
||||
* At this point we know that the number will start a new interval
|
||||
* which needs to be added to the list. We might have to recyle an
|
||||
* older entry in the list.
|
||||
*/
|
||||
|
||||
if (list.size() < MAX_INTERVALS) {
|
||||
entry = new Entry(number);
|
||||
if (prevEntryPos < windowStartIndex)
|
||||
windowStartIndex++; // due to the insertion which will happen
|
||||
} else {
|
||||
/*
|
||||
* Delete the entry that marks the start of the current window.
|
||||
* The marker will automatically point to the next entry in the
|
||||
* list when this happens. If the current entry is at the end
|
||||
* of the list then set the marker to the start of the list.
|
||||
*/
|
||||
int oldWindowStartIndex = windowStartIndex;
|
||||
if (windowStartIndex == (list.size() - 1))
|
||||
windowStartIndex = 0;
|
||||
|
||||
entry = list.remove(oldWindowStartIndex);
|
||||
windowStart = list.get(windowStartIndex).getStart();
|
||||
entry.setStart(number);
|
||||
entry.setEnd(number);
|
||||
|
||||
if (prevEntryPos >= oldWindowStartIndex) {
|
||||
prevEntryPos--; // due to the deletion that just happened
|
||||
} else {
|
||||
/*
|
||||
* If the start of the current window just moved from the
|
||||
* end of the list to the front of the list, and if the new
|
||||
* entry will be added to the front of the list, then
|
||||
* the new entry is the actual window start.
|
||||
* eg, Consider { [-10, -8], ..., [-6, -3], [3, 9]}. In
|
||||
* this list, suppose the element [3, 9] is the start of
|
||||
* the window and has to be deleted to make place to add
|
||||
* [-12, -12]. The resultant list will be
|
||||
* {[-12, -12], [-10, -8], ..., [-6, -3]} and the new start
|
||||
* of the window should be the element [-12, -12], not
|
||||
* [-10, -8] which succeeded [3, 9] in the old list.
|
||||
*/
|
||||
if (oldWindowStartIndex != windowStartIndex) {
|
||||
// windowStartIndex is 0 at this point
|
||||
if (prevEntryPos == -1)
|
||||
// The new entry is going to the front
|
||||
windowStart = number;
|
||||
} else {
|
||||
// due to the insertion which will happen:
|
||||
windowStartIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we are ready to actually add to the list at index
|
||||
// 'prevEntryPos+1'
|
||||
|
||||
list.add(prevEntryPos+1, entry);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("TokenTracker: ");
|
||||
buf.append(" initNumber=").append(initNumber);
|
||||
buf.append(" windowStart=").append(windowStart);
|
||||
buf.append(" expectedNumber=").append(expectedNumber);
|
||||
buf.append(" windowStartIndex=").append(windowStartIndex);
|
||||
buf.append("\n\tIntervals are: {");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i != 0)
|
||||
buf.append(", ");
|
||||
buf.append(list.get(i).toString());
|
||||
}
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry in the list that represents the sequence of received
|
||||
* tokens. Each entry is actaully an interval of numbers, all of which
|
||||
* have been received.
|
||||
*/
|
||||
class Entry {
|
||||
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
Entry(int number) {
|
||||
start = number;
|
||||
end = number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns -1 if this interval represented by this entry precedes
|
||||
* the number, 0 if the the number is contained in the interval,
|
||||
* and -1 if the interval occurs after the number.
|
||||
*/
|
||||
final int compareTo(int number) {
|
||||
if (start > number)
|
||||
return 1;
|
||||
else if (end < number)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
final boolean contains(int number) {
|
||||
return (number >= start &&
|
||||
number <= end);
|
||||
}
|
||||
|
||||
final void append(int number) {
|
||||
if (number == (end + 1))
|
||||
end = number;
|
||||
}
|
||||
|
||||
final void setInterval(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
final void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
final void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
final int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
final int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("[" + start + ", " + end + "]");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
115
jdkSrc/jdk8/sun/security/jgss/krb5/AcceptSecContextToken.java
Normal file
115
jdkSrc/jdk8/sun/security/jgss/krb5/AcceptSecContextToken.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.krb5.*;
|
||||
|
||||
class AcceptSecContextToken extends InitialToken {
|
||||
|
||||
private KrbApRep apRep = null;
|
||||
|
||||
/**
|
||||
* Creates an AcceptSecContextToken for the context acceptor to send to
|
||||
* the context initiator.
|
||||
*/
|
||||
public AcceptSecContextToken(Krb5Context context,
|
||||
KrbApReq apReq)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
boolean useSubkey = AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.security.krb5.acceptor.subkey"));
|
||||
|
||||
boolean useSequenceNumber = true;
|
||||
|
||||
EncryptionKey subKey = null;
|
||||
if (useSubkey) {
|
||||
subKey = new EncryptionKey(apReq.getCreds().getSessionKey());
|
||||
context.setKey(Krb5Context.ACCEPTOR_SUBKEY, subKey);
|
||||
}
|
||||
apRep = new KrbApRep(apReq, useSequenceNumber, subKey);
|
||||
|
||||
context.resetMySequenceNumber(apRep.getSeqNumber().intValue());
|
||||
|
||||
/*
|
||||
* Note: The acceptor side context key was set when the
|
||||
* InitSecContextToken was received.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AcceptSecContextToken at the context initiator's side
|
||||
* using the bytes received from the acceptor.
|
||||
*/
|
||||
public AcceptSecContextToken(Krb5Context context,
|
||||
Credentials serviceCreds, KrbApReq apReq,
|
||||
InputStream is)
|
||||
throws IOException, GSSException, KrbException {
|
||||
|
||||
int tokenId = ((is.read()<<8) | is.read());
|
||||
|
||||
if (tokenId != Krb5Token.AP_REP_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"AP_REP token id does not match!");
|
||||
|
||||
byte[] apRepBytes =
|
||||
new sun.security.util.DerValue(is).toByteArray();
|
||||
|
||||
KrbApRep apRep = new KrbApRep(apRepBytes, serviceCreds, apReq);
|
||||
|
||||
/*
|
||||
* Allow the context acceptor to set a subkey if desired, even
|
||||
* though our context acceptor will not do so.
|
||||
*/
|
||||
EncryptionKey subKey = apRep.getSubKey();
|
||||
if (subKey != null) {
|
||||
context.setKey(Krb5Context.ACCEPTOR_SUBKEY, subKey);
|
||||
/*
|
||||
System.out.println("\n\nSub-Session key from AP-REP is: " +
|
||||
getHexBytes(subKey.getBytes()) + "\n");
|
||||
*/
|
||||
}
|
||||
|
||||
Integer apRepSeqNumber = apRep.getSeqNumber();
|
||||
int peerSeqNumber = (apRepSeqNumber != null ?
|
||||
apRepSeqNumber.intValue() :
|
||||
0);
|
||||
context.resetPeerSequenceNumber(peerSeqNumber);
|
||||
}
|
||||
|
||||
public final byte[] encode() throws IOException {
|
||||
byte[] apRepBytes = apRep.getMessage();
|
||||
byte[] retVal = new byte[2 + apRepBytes.length];
|
||||
writeInt(Krb5Token.AP_REP_ID, retVal, 0);
|
||||
System.arraycopy(apRepBytes, 0, retVal, 2, apRepBytes.length);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
1502
jdkSrc/jdk8/sun/security/jgss/krb5/CipherHelper.java
Normal file
1502
jdkSrc/jdk8/sun/security/jgss/krb5/CipherHelper.java
Normal file
File diff suppressed because it is too large
Load Diff
215
jdkSrc/jdk8/sun/security/jgss/krb5/InitSecContextToken.java
Normal file
215
jdkSrc/jdk8/sun/security/jgss/krb5/InitSecContextToken.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import com.sun.security.jgss.AuthorizationDataEntry;
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.krb5.*;
|
||||
import java.net.InetAddress;
|
||||
import sun.security.krb5.internal.AuthorizationData;
|
||||
import sun.security.krb5.internal.KerberosTime;
|
||||
|
||||
class InitSecContextToken extends InitialToken {
|
||||
|
||||
// If non-mutual authentication is requested, there is no AP-REP message.
|
||||
// The acceptor thus has no chance to send the seq-number field to the
|
||||
// initiator. In this case, the initiator and acceptor should has an
|
||||
// agreement to derive acceptor's initial seq-number if the acceptor wishes
|
||||
// to send messages to the initiator.
|
||||
|
||||
// If this flag is true, it will the same as the initiator's initial
|
||||
// seq-number (as MIT krb5 and Windows SSPI do). Otherwise, it will be zero
|
||||
// (as Heimdal does). The default value is true.
|
||||
private static final boolean ACCEPTOR_USE_INITIATOR_SEQNUM;
|
||||
|
||||
static {
|
||||
// The ACCEPTOR_USE_INITIATOR_SEQNUM value is determined by the system
|
||||
// property "sun.security.krb5.acceptor.sequence.number.nonmutual",
|
||||
// which can be set to "initiator", "zero" or "0".
|
||||
String propName = "sun.security.krb5.acceptor.sequence.number.nonmutual";
|
||||
String s = GetPropertyAction.privilegedGetProperty(propName, "initiator");
|
||||
if (s.equals("initiator")) {
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM = true;
|
||||
} else if (s.equals("zero") || s.equals("0")) {
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM = false;
|
||||
} else {
|
||||
throw new AssertionError("Unrecognized value for " + propName
|
||||
+ ": " + s);
|
||||
}
|
||||
}
|
||||
|
||||
private KrbApReq apReq = null;
|
||||
|
||||
/**
|
||||
* For the context initiator to call. It constructs a new
|
||||
* InitSecContextToken to send over to the peer containing the desired
|
||||
* flags and the AP-REQ. It also updates the context with the local
|
||||
* sequence number and shared context key.
|
||||
* (When mutual auth is enabled the peer has an opportunity to
|
||||
* renegotiate the session key in the followup AcceptSecContextToken
|
||||
* that it sends.)
|
||||
*/
|
||||
InitSecContextToken(Krb5Context context,
|
||||
Credentials tgt,
|
||||
Credentials serviceTicket)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
boolean mutualRequired = context.getMutualAuthState();
|
||||
boolean useSubkey = true; // MIT Impl will crash if this is not set!
|
||||
boolean useSequenceNumber = true;
|
||||
|
||||
OverloadedChecksum gssChecksum =
|
||||
new OverloadedChecksum(context, tgt, serviceTicket);
|
||||
|
||||
Checksum checksum = gssChecksum.getChecksum();
|
||||
|
||||
context.setTktFlags(serviceTicket.getFlags());
|
||||
context.setAuthTime(
|
||||
new KerberosTime(serviceTicket.getAuthTime()).toString());
|
||||
apReq = new KrbApReq(serviceTicket,
|
||||
mutualRequired,
|
||||
useSubkey,
|
||||
useSequenceNumber,
|
||||
checksum);
|
||||
|
||||
context.resetMySequenceNumber(apReq.getSeqNumber().intValue());
|
||||
|
||||
EncryptionKey subKey = apReq.getSubKey();
|
||||
if (subKey != null)
|
||||
context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey);
|
||||
else
|
||||
context.setKey(Krb5Context.SESSION_KEY, serviceTicket.getSessionKey());
|
||||
|
||||
if (!mutualRequired)
|
||||
context.resetPeerSequenceNumber(
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM
|
||||
? apReq.getSeqNumber().intValue()
|
||||
: 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the context acceptor to call. It reads the bytes out of an
|
||||
* InputStream and constructs an InitSecContextToken with them.
|
||||
*/
|
||||
InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred,
|
||||
InputStream is)
|
||||
throws IOException, GSSException, KrbException {
|
||||
|
||||
int tokenId = ((is.read()<<8) | is.read());
|
||||
|
||||
if (tokenId != Krb5Token.AP_REQ_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"AP_REQ token id does not match!");
|
||||
|
||||
// XXX Modify KrbApReq cons to take an InputStream
|
||||
byte[] apReqBytes =
|
||||
new sun.security.util.DerValue(is).toByteArray();
|
||||
//debug("=====ApReqBytes: [" + getHexBytes(apReqBytes) + "]\n");
|
||||
|
||||
InetAddress addr = null;
|
||||
if (context.getChannelBinding() != null) {
|
||||
addr = context.getChannelBinding().getInitiatorAddress();
|
||||
}
|
||||
apReq = new KrbApReq(apReqBytes, cred, addr);
|
||||
//debug("\nReceived AP-REQ and authenticated it.\n");
|
||||
|
||||
EncryptionKey sessionKey = apReq.getCreds().getSessionKey();
|
||||
|
||||
/*
|
||||
System.out.println("\n\nSession key from service ticket is: " +
|
||||
getHexBytes(sessionKey.getBytes()));
|
||||
*/
|
||||
|
||||
EncryptionKey subKey = apReq.getSubKey();
|
||||
if (subKey != null) {
|
||||
context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey);
|
||||
/*
|
||||
System.out.println("Sub-Session key from authenticator is: " +
|
||||
getHexBytes(subKey.getBytes()) + "\n");
|
||||
*/
|
||||
} else {
|
||||
context.setKey(Krb5Context.SESSION_KEY, sessionKey);
|
||||
//System.out.println("Sub-Session Key Missing in Authenticator.\n");
|
||||
}
|
||||
|
||||
OverloadedChecksum gssChecksum = new OverloadedChecksum(
|
||||
context, apReq.getChecksum(), sessionKey, subKey);
|
||||
gssChecksum.setContextFlags(context);
|
||||
Credentials delegCred = gssChecksum.getDelegatedCreds();
|
||||
if (delegCred != null) {
|
||||
Krb5CredElement credElement =
|
||||
Krb5InitCredential.getInstance(
|
||||
(Krb5NameElement)context.getSrcName(),
|
||||
delegCred);
|
||||
context.setDelegCred(credElement);
|
||||
}
|
||||
|
||||
Integer apReqSeqNumber = apReq.getSeqNumber();
|
||||
int peerSeqNumber = (apReqSeqNumber != null ?
|
||||
apReqSeqNumber.intValue() :
|
||||
0);
|
||||
context.resetPeerSequenceNumber(peerSeqNumber);
|
||||
if (!context.getMutualAuthState()) {
|
||||
context.resetMySequenceNumber(
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM
|
||||
? peerSeqNumber
|
||||
: 0);
|
||||
}
|
||||
context.setAuthTime(
|
||||
new KerberosTime(apReq.getCreds().getAuthTime()).toString());
|
||||
context.setTktFlags(apReq.getCreds().getFlags());
|
||||
AuthorizationData ad = apReq.getCreds().getAuthzData();
|
||||
if (ad == null) {
|
||||
context.setAuthzData(null);
|
||||
} else {
|
||||
AuthorizationDataEntry[] authzData =
|
||||
new AuthorizationDataEntry[ad.count()];
|
||||
for (int i=0; i<ad.count(); i++) {
|
||||
authzData[i] = new AuthorizationDataEntry(
|
||||
ad.item(i).adType, ad.item(i).adData);
|
||||
}
|
||||
context.setAuthzData(authzData);
|
||||
}
|
||||
}
|
||||
|
||||
public final KrbApReq getKrbApReq() {
|
||||
return apReq;
|
||||
}
|
||||
|
||||
public final byte[] encode() throws IOException {
|
||||
byte[] apReqBytes = apReq.getMessage();
|
||||
byte[] retVal = new byte[2 + apReqBytes.length];
|
||||
writeInt(Krb5Token.AP_REQ_ID, retVal, 0);
|
||||
System.arraycopy(apReqBytes, 0, retVal, 2, apReqBytes.length);
|
||||
// System.out.println("GSS-Token with AP_REQ is:");
|
||||
// System.out.println(getHexBytes(retVal));
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
453
jdkSrc/jdk8/sun/security/jgss/krb5/InitialToken.java
Normal file
453
jdkSrc/jdk8/sun/security/jgss/krb5/InitialToken.java
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import javax.security.auth.kerberos.DelegationPermission;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.Krb5;
|
||||
|
||||
abstract class InitialToken extends Krb5Token {
|
||||
|
||||
private static final int CHECKSUM_TYPE = 0x8003;
|
||||
|
||||
private static final int CHECKSUM_LENGTH_SIZE = 4;
|
||||
private static final int CHECKSUM_BINDINGS_SIZE = 16;
|
||||
private static final int CHECKSUM_FLAGS_SIZE = 4;
|
||||
private static final int CHECKSUM_DELEG_OPT_SIZE = 2;
|
||||
private static final int CHECKSUM_DELEG_LGTH_SIZE = 2;
|
||||
|
||||
private static final int CHECKSUM_DELEG_FLAG = 1;
|
||||
private static final int CHECKSUM_MUTUAL_FLAG = 2;
|
||||
private static final int CHECKSUM_REPLAY_FLAG = 4;
|
||||
private static final int CHECKSUM_SEQUENCE_FLAG = 8;
|
||||
private static final int CHECKSUM_CONF_FLAG = 16;
|
||||
private static final int CHECKSUM_INTEG_FLAG = 32;
|
||||
|
||||
private final byte[] CHECKSUM_FIRST_BYTES =
|
||||
{(byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00};
|
||||
|
||||
private static final int CHANNEL_BINDING_AF_INET = 2;
|
||||
private static final int CHANNEL_BINDING_AF_INET6 = 24;
|
||||
private static final int CHANNEL_BINDING_AF_NULL_ADDR = 255;
|
||||
|
||||
private static final int Inet4_ADDRSZ = 4;
|
||||
private static final int Inet6_ADDRSZ = 16;
|
||||
|
||||
protected class OverloadedChecksum {
|
||||
|
||||
private byte[] checksumBytes = null;
|
||||
private Credentials delegCreds = null;
|
||||
private int flags = 0;
|
||||
|
||||
/**
|
||||
* Called on the initiator side when creating the
|
||||
* InitSecContextToken.
|
||||
*/
|
||||
public OverloadedChecksum(Krb5Context context,
|
||||
Credentials tgt,
|
||||
Credentials serviceTicket)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
byte[] krbCredMessage = null;
|
||||
int pos = 0;
|
||||
int size = CHECKSUM_LENGTH_SIZE + CHECKSUM_BINDINGS_SIZE +
|
||||
CHECKSUM_FLAGS_SIZE;
|
||||
|
||||
if (!tgt.isForwardable()) {
|
||||
context.setCredDelegState(false);
|
||||
context.setDelegPolicyState(false);
|
||||
} else if (context.getCredDelegState()) {
|
||||
if (context.getDelegPolicyState()) {
|
||||
if (!serviceTicket.checkDelegate()) {
|
||||
// delegation not permitted by server policy, mark it
|
||||
context.setDelegPolicyState(false);
|
||||
}
|
||||
}
|
||||
} else if (context.getDelegPolicyState()) {
|
||||
if (serviceTicket.checkDelegate()) {
|
||||
context.setCredDelegState(true);
|
||||
} else {
|
||||
context.setDelegPolicyState(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.getCredDelegState()) {
|
||||
KrbCred krbCred = null;
|
||||
CipherHelper cipherHelper =
|
||||
context.getCipherHelper(serviceTicket.getSessionKey());
|
||||
if (useNullKey(cipherHelper)) {
|
||||
krbCred = new KrbCred(tgt, serviceTicket,
|
||||
EncryptionKey.NULL_KEY);
|
||||
} else {
|
||||
krbCred = new KrbCred(tgt, serviceTicket,
|
||||
serviceTicket.getSessionKey());
|
||||
}
|
||||
krbCredMessage = krbCred.getMessage();
|
||||
size += CHECKSUM_DELEG_OPT_SIZE +
|
||||
CHECKSUM_DELEG_LGTH_SIZE +
|
||||
krbCredMessage.length;
|
||||
}
|
||||
|
||||
checksumBytes = new byte[size];
|
||||
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[0];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[1];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[2];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[3];
|
||||
|
||||
ChannelBinding localBindings = context.getChannelBinding();
|
||||
if (localBindings != null) {
|
||||
byte[] localBindingsBytes =
|
||||
computeChannelBinding(context.getChannelBinding());
|
||||
System.arraycopy(localBindingsBytes, 0,
|
||||
checksumBytes, pos, localBindingsBytes.length);
|
||||
// System.out.println("ChannelBinding hash: "
|
||||
// + getHexBytes(localBindingsBytes));
|
||||
}
|
||||
|
||||
pos += CHECKSUM_BINDINGS_SIZE;
|
||||
|
||||
if (context.getCredDelegState())
|
||||
flags |= CHECKSUM_DELEG_FLAG;
|
||||
if (context.getMutualAuthState())
|
||||
flags |= CHECKSUM_MUTUAL_FLAG;
|
||||
if (context.getReplayDetState())
|
||||
flags |= CHECKSUM_REPLAY_FLAG;
|
||||
if (context.getSequenceDetState())
|
||||
flags |= CHECKSUM_SEQUENCE_FLAG;
|
||||
if (context.getIntegState())
|
||||
flags |= CHECKSUM_INTEG_FLAG;
|
||||
if (context.getConfState())
|
||||
flags |= CHECKSUM_CONF_FLAG;
|
||||
|
||||
byte[] temp = new byte[4];
|
||||
writeLittleEndian(flags, temp);
|
||||
checksumBytes[pos++] = temp[0];
|
||||
checksumBytes[pos++] = temp[1];
|
||||
checksumBytes[pos++] = temp[2];
|
||||
checksumBytes[pos++] = temp[3];
|
||||
|
||||
if (context.getCredDelegState()) {
|
||||
|
||||
PrincipalName delegateTo =
|
||||
serviceTicket.getServer();
|
||||
// Cannot use '\"' instead of "\"" in constructor because
|
||||
// it is interpreted as suggested length!
|
||||
StringBuffer buf = new StringBuffer("\"");
|
||||
buf.append(delegateTo.getName()).append('\"');
|
||||
String realm = delegateTo.getRealmAsString();
|
||||
buf.append(" \"krbtgt/").append(realm).append('@');
|
||||
buf.append(realm).append('\"');
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
DelegationPermission perm =
|
||||
new DelegationPermission(buf.toString());
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write 1 in little endian but in two bytes
|
||||
* for DlgOpt
|
||||
*/
|
||||
|
||||
checksumBytes[pos++] = (byte)0x01;
|
||||
checksumBytes[pos++] = (byte)0x00;
|
||||
|
||||
/*
|
||||
* Write the length of the delegated credential in little
|
||||
* endian but in two bytes for Dlgth
|
||||
*/
|
||||
|
||||
if (krbCredMessage.length > 0x0000ffff)
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect message length");
|
||||
|
||||
writeLittleEndian(krbCredMessage.length, temp);
|
||||
checksumBytes[pos++] = temp[0];
|
||||
checksumBytes[pos++] = temp[1];
|
||||
System.arraycopy(krbCredMessage, 0,
|
||||
checksumBytes, pos, krbCredMessage.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on the acceptor side when reading an InitSecContextToken.
|
||||
*/
|
||||
// XXX Passing in Checksum is not required. byte[] can
|
||||
// be passed in if this checksum type denotes a
|
||||
// raw_checksum. In that case, make Checksum class krb5
|
||||
// internal.
|
||||
public OverloadedChecksum(Krb5Context context, Checksum checksum,
|
||||
EncryptionKey key, EncryptionKey subKey)
|
||||
throws GSSException, KrbException, IOException {
|
||||
|
||||
int pos = 0;
|
||||
|
||||
if (checksum == null) {
|
||||
GSSException ge = new GSSException(GSSException.FAILURE, -1,
|
||||
"No cksum in AP_REQ's authenticator");
|
||||
ge.initCause(new KrbException(Krb5.KRB_AP_ERR_INAPP_CKSUM));
|
||||
throw ge;
|
||||
}
|
||||
checksumBytes = checksum.getBytes();
|
||||
|
||||
if ((checksumBytes[0] != CHECKSUM_FIRST_BYTES[0]) ||
|
||||
(checksumBytes[1] != CHECKSUM_FIRST_BYTES[1]) ||
|
||||
(checksumBytes[2] != CHECKSUM_FIRST_BYTES[2]) ||
|
||||
(checksumBytes[3] != CHECKSUM_FIRST_BYTES[3])) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect checksum");
|
||||
}
|
||||
|
||||
ChannelBinding localBindings = context.getChannelBinding();
|
||||
|
||||
// Ignore remote channel binding info when not requested at
|
||||
// local side (RFC 4121 4.1.1.2: the acceptor MAY ignore...).
|
||||
//
|
||||
// All major krb5 implementors implement this "MAY",
|
||||
// and some applications depend on it as a workaround
|
||||
// for not having a way to negotiate the use of channel
|
||||
// binding -- the initiator application always uses CB
|
||||
// and hopes the acceptor will ignore the CB if the
|
||||
// acceptor doesn't support CB.
|
||||
if (localBindings != null) {
|
||||
byte[] remoteBindingBytes = new byte[CHECKSUM_BINDINGS_SIZE];
|
||||
System.arraycopy(checksumBytes, 4, remoteBindingBytes, 0,
|
||||
CHECKSUM_BINDINGS_SIZE);
|
||||
|
||||
byte[] noBindings = new byte[CHECKSUM_BINDINGS_SIZE];
|
||||
if (!Arrays.equals(noBindings, remoteBindingBytes)) {
|
||||
byte[] localBindingsBytes =
|
||||
computeChannelBinding(localBindings);
|
||||
if (!Arrays.equals(localBindingsBytes,
|
||||
remoteBindingBytes)) {
|
||||
throw new GSSException(GSSException.BAD_BINDINGS, -1,
|
||||
"Bytes mismatch!");
|
||||
}
|
||||
} else {
|
||||
throw new GSSException(GSSException.BAD_BINDINGS, -1,
|
||||
"Token missing ChannelBinding!");
|
||||
}
|
||||
}
|
||||
|
||||
flags = readLittleEndian(checksumBytes, 20, 4);
|
||||
|
||||
if ((flags & CHECKSUM_DELEG_FLAG) > 0) {
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* if ((checksumBytes[24] != (byte)0x01) &&
|
||||
* (checksumBytes[25] != (byte)0x00))
|
||||
*/
|
||||
|
||||
int credLen = readLittleEndian(checksumBytes, 26, 2);
|
||||
byte[] credBytes = new byte[credLen];
|
||||
System.arraycopy(checksumBytes, 28, credBytes, 0, credLen);
|
||||
|
||||
KrbCred cred;
|
||||
try {
|
||||
cred = new KrbCred(credBytes, key);
|
||||
} catch (KrbException ke) {
|
||||
if (subKey != null) {
|
||||
cred = new KrbCred(credBytes, subKey);
|
||||
} else {
|
||||
throw ke;
|
||||
}
|
||||
}
|
||||
delegCreds = cred.getDelegatedCreds()[0];
|
||||
}
|
||||
}
|
||||
|
||||
// check if KRB-CRED message should use NULL_KEY for encryption
|
||||
private boolean useNullKey(CipherHelper ch) {
|
||||
boolean flag = true;
|
||||
// for "newer" etypes and RC4-HMAC do not use NULL KEY
|
||||
if ((ch.getProto() == 1) || ch.isArcFour()) {
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public Checksum getChecksum() throws KrbException {
|
||||
return new Checksum(checksumBytes, CHECKSUM_TYPE);
|
||||
}
|
||||
|
||||
public Credentials getDelegatedCreds() {
|
||||
return delegCreds;
|
||||
}
|
||||
|
||||
// Only called by acceptor
|
||||
public void setContextFlags(Krb5Context context) {
|
||||
// default for cred delegation is false
|
||||
if ((flags & CHECKSUM_DELEG_FLAG) > 0)
|
||||
context.setCredDelegState(true);
|
||||
// default for the following are true
|
||||
if ((flags & CHECKSUM_MUTUAL_FLAG) == 0) {
|
||||
context.setMutualAuthState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_REPLAY_FLAG) == 0) {
|
||||
context.setReplayDetState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_SEQUENCE_FLAG) == 0) {
|
||||
context.setSequenceDetState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_CONF_FLAG) == 0) {
|
||||
context.setConfState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_INTEG_FLAG) == 0) {
|
||||
context.setIntegState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getAddrType(InetAddress addr) {
|
||||
int addressType = CHANNEL_BINDING_AF_NULL_ADDR;
|
||||
|
||||
if (addr instanceof Inet4Address)
|
||||
addressType = CHANNEL_BINDING_AF_INET;
|
||||
else if (addr instanceof Inet6Address)
|
||||
addressType = CHANNEL_BINDING_AF_INET6;
|
||||
return (addressType);
|
||||
}
|
||||
|
||||
private byte[] getAddrBytes(InetAddress addr) throws GSSException {
|
||||
int addressType = getAddrType(addr);
|
||||
byte[] addressBytes = addr.getAddress();
|
||||
if (addressBytes != null) {
|
||||
switch (addressType) {
|
||||
case CHANNEL_BINDING_AF_INET:
|
||||
if (addressBytes.length != Inet4_ADDRSZ) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect AF-INET address length in ChannelBinding.");
|
||||
}
|
||||
return (addressBytes);
|
||||
case CHANNEL_BINDING_AF_INET6:
|
||||
if (addressBytes.length != Inet6_ADDRSZ) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect AF-INET6 address length in ChannelBinding.");
|
||||
}
|
||||
return (addressBytes);
|
||||
default:
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Cannot handle non AF-INET addresses in ChannelBinding.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] computeChannelBinding(ChannelBinding channelBinding)
|
||||
throws GSSException {
|
||||
|
||||
InetAddress initiatorAddress = channelBinding.getInitiatorAddress();
|
||||
InetAddress acceptorAddress = channelBinding.getAcceptorAddress();
|
||||
int size = 5*4;
|
||||
|
||||
int initiatorAddressType = getAddrType(initiatorAddress);
|
||||
int acceptorAddressType = getAddrType(acceptorAddress);
|
||||
|
||||
byte[] initiatorAddressBytes = null;
|
||||
if (initiatorAddress != null) {
|
||||
initiatorAddressBytes = getAddrBytes(initiatorAddress);
|
||||
size += initiatorAddressBytes.length;
|
||||
}
|
||||
|
||||
byte[] acceptorAddressBytes = null;
|
||||
if (acceptorAddress != null) {
|
||||
acceptorAddressBytes = getAddrBytes(acceptorAddress);
|
||||
size += acceptorAddressBytes.length;
|
||||
}
|
||||
|
||||
byte[] appDataBytes = channelBinding.getApplicationData();
|
||||
if (appDataBytes != null) {
|
||||
size += appDataBytes.length;
|
||||
}
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
int pos = 0;
|
||||
|
||||
writeLittleEndian(initiatorAddressType, data, pos);
|
||||
pos += 4;
|
||||
|
||||
if (initiatorAddressBytes != null) {
|
||||
writeLittleEndian(initiatorAddressBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(initiatorAddressBytes, 0,
|
||||
data, pos, initiatorAddressBytes.length);
|
||||
pos += initiatorAddressBytes.length;
|
||||
} else {
|
||||
// Write length 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
writeLittleEndian(acceptorAddressType, data, pos);
|
||||
pos += 4;
|
||||
|
||||
if (acceptorAddressBytes != null) {
|
||||
writeLittleEndian(acceptorAddressBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(acceptorAddressBytes, 0,
|
||||
data, pos, acceptorAddressBytes.length);
|
||||
pos += acceptorAddressBytes.length;
|
||||
} else {
|
||||
// Write length 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
if (appDataBytes != null) {
|
||||
writeLittleEndian(appDataBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(appDataBytes, 0, data, pos,
|
||||
appDataBytes.length);
|
||||
pos += appDataBytes.length;
|
||||
} else {
|
||||
// Write 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
try {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
return md5.digest(data);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not get MD5 Message Digest - "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract byte[] encode() throws IOException;
|
||||
|
||||
}
|
||||
197
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5AcceptCredential.java
Normal file
197
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5AcceptCredential.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
/**
|
||||
* Implements the krb5 acceptor credential element.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
public class Krb5AcceptCredential
|
||||
implements Krb5CredElement {
|
||||
|
||||
private final Krb5NameElement name;
|
||||
private final ServiceCreds screds;
|
||||
|
||||
private Krb5AcceptCredential(Krb5NameElement name, ServiceCreds creds) {
|
||||
/*
|
||||
* Initialize this instance with the data from the acquired
|
||||
* KerberosKey. This class needs to be a KerberosKey too
|
||||
* hence we can't just store a reference.
|
||||
*/
|
||||
|
||||
this.name = name;
|
||||
this.screds = creds;
|
||||
}
|
||||
|
||||
static Krb5AcceptCredential getInstance(final GSSCaller caller, Krb5NameElement name)
|
||||
throws GSSException {
|
||||
|
||||
final String serverPrinc = (name == null? null:
|
||||
name.getKrb5PrincipalName().getName());
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
ServiceCreds creds = null;
|
||||
try {
|
||||
creds = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<ServiceCreds>() {
|
||||
public ServiceCreds run() throws Exception {
|
||||
return Krb5Util.getServiceCreds(
|
||||
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
|
||||
serverPrinc, acc);
|
||||
}});
|
||||
} catch (PrivilegedActionException e) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.NO_CRED, -1,
|
||||
"Attempt to obtain new ACCEPT credentials failed!");
|
||||
ge.initCause(e.getException());
|
||||
throw ge;
|
||||
}
|
||||
|
||||
if (creds == null)
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
"Failed to find any Kerberos credentails");
|
||||
|
||||
if (name == null) {
|
||||
String fullName = creds.getName();
|
||||
if (fullName != null) {
|
||||
name = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
}
|
||||
|
||||
return new Krb5AcceptCredential(name, creds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final GSSNameSpi getName() throws GSSException {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return GSSCredential.INDEFINITE_LIFETIME;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
public EncryptionKey[] getKrb5EncryptionKeys(PrincipalName princ) {
|
||||
return screds.getEKeys(princ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element.
|
||||
*/
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
destroy();
|
||||
} catch (DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the locally cached EncryptionKey value and then calls
|
||||
* destroy in the base class.
|
||||
*/
|
||||
public void destroy() throws DestroyFailedException {
|
||||
screds.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonation is only available on the initiator side. The
|
||||
* service must starts as an initiator to get an initial TGT to complete
|
||||
* the S4U2self protocol.
|
||||
*/
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
Credentials cred = screds.getInitCred();
|
||||
if (cred != null) {
|
||||
return Krb5InitCredential.getInstance(this.name, cred)
|
||||
.impersonate(name);
|
||||
} else {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Only an initiate credentials can impersonate");
|
||||
}
|
||||
}
|
||||
}
|
||||
1454
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Context.java
Normal file
1454
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Context.java
Normal file
File diff suppressed because it is too large
Load Diff
41
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5CredElement.java
Normal file
41
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5CredElement.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* Provides type safety for Krb5 credential elements.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
interface Krb5CredElement
|
||||
extends GSSCredentialSpi {
|
||||
}
|
||||
406
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5InitCredential.java
Normal file
406
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5InitCredential.java
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.Config;
|
||||
import javax.security.auth.kerberos.*;
|
||||
import java.net.InetAddress;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
|
||||
/**
|
||||
* Implements the krb5 initiator credential element.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @author Ram Marti
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class Krb5InitCredential
|
||||
extends KerberosTicket
|
||||
implements Krb5CredElement {
|
||||
|
||||
private static final long serialVersionUID = 7723415700837898232L;
|
||||
|
||||
private Krb5NameElement name;
|
||||
private Credentials krb5Credentials;
|
||||
public KerberosTicket proxyTicket;
|
||||
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
Date authTime,
|
||||
Date startTime,
|
||||
Date endTime,
|
||||
Date renewTill,
|
||||
InetAddress[] clientAddresses)
|
||||
throws GSSException {
|
||||
super(asn1Encoding,
|
||||
client,
|
||||
server,
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(this, clientAlias);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(this, serverAlias);
|
||||
this.name = name;
|
||||
|
||||
try {
|
||||
// Cache this for later use by the sun.security.krb5 package.
|
||||
krb5Credentials = new Credentials(asn1Encoding,
|
||||
client.getName(),
|
||||
(clientAlias != null ?
|
||||
clientAlias.getName() : null),
|
||||
server.getName(),
|
||||
(serverAlias != null ?
|
||||
serverAlias.getName() : null),
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
} catch (KrbException e) {
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
Credentials delegatedCred,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
Date authTime,
|
||||
Date startTime,
|
||||
Date endTime,
|
||||
Date renewTill,
|
||||
InetAddress[] clientAddresses)
|
||||
throws GSSException {
|
||||
super(asn1Encoding,
|
||||
client,
|
||||
server,
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(this, clientAlias);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(this, serverAlias);
|
||||
this.name = name;
|
||||
// A delegated cred does not have all fields set. So do not try to
|
||||
// creat new Credentials out of the delegatedCred.
|
||||
this.krb5Credentials = delegatedCred;
|
||||
}
|
||||
|
||||
static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name,
|
||||
int initLifetime)
|
||||
throws GSSException {
|
||||
|
||||
KerberosTicket tgt = getTgt(caller, name, initLifetime);
|
||||
if (tgt == null)
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
"Failed to find any Kerberos tgt");
|
||||
|
||||
if (name == null) {
|
||||
String fullName = tgt.getClient().getName();
|
||||
name = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
|
||||
KerberosPrincipal clientAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetClientAlias(tgt);
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(tgt);
|
||||
Krb5InitCredential result = new Krb5InitCredential(name,
|
||||
tgt.getEncoded(),
|
||||
tgt.getClient(),
|
||||
clientAlias,
|
||||
tgt.getServer(),
|
||||
serverAlias,
|
||||
tgt.getSessionKey().getEncoded(),
|
||||
tgt.getSessionKeyType(),
|
||||
tgt.getFlags(),
|
||||
tgt.getAuthTime(),
|
||||
tgt.getStartTime(),
|
||||
tgt.getEndTime(),
|
||||
tgt.getRenewTill(),
|
||||
tgt.getClientAddresses());
|
||||
result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
|
||||
kerberosTicketGetProxy(tgt);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Krb5InitCredential getInstance(Krb5NameElement name,
|
||||
Credentials delegatedCred)
|
||||
throws GSSException {
|
||||
|
||||
EncryptionKey sessionKey = delegatedCred.getSessionKey();
|
||||
|
||||
/*
|
||||
* all of the following data is optional in a KRB-CRED
|
||||
* messages. This check for each field.
|
||||
*/
|
||||
|
||||
PrincipalName cPrinc = delegatedCred.getClient();
|
||||
PrincipalName cAPrinc = delegatedCred.getClientAlias();
|
||||
PrincipalName sPrinc = delegatedCred.getServer();
|
||||
PrincipalName sAPrinc = delegatedCred.getServerAlias();
|
||||
|
||||
KerberosPrincipal client = null;
|
||||
KerberosPrincipal clientAlias = null;
|
||||
KerberosPrincipal server = null;
|
||||
KerberosPrincipal serverAlias = null;
|
||||
|
||||
Krb5NameElement credName = null;
|
||||
|
||||
if (cPrinc != null) {
|
||||
String fullName = cPrinc.getName();
|
||||
credName = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
client = new KerberosPrincipal(fullName);
|
||||
}
|
||||
|
||||
if (cAPrinc != null) {
|
||||
clientAlias = new KerberosPrincipal(cAPrinc.getName());
|
||||
}
|
||||
|
||||
// XXX Compare name to credName
|
||||
|
||||
if (sPrinc != null) {
|
||||
server =
|
||||
new KerberosPrincipal(sPrinc.getName(),
|
||||
KerberosPrincipal.KRB_NT_SRV_INST);
|
||||
}
|
||||
|
||||
if (sAPrinc != null) {
|
||||
serverAlias = new KerberosPrincipal(sAPrinc.getName());
|
||||
}
|
||||
|
||||
return new Krb5InitCredential(credName,
|
||||
delegatedCred,
|
||||
delegatedCred.getEncoded(),
|
||||
client,
|
||||
clientAlias,
|
||||
server,
|
||||
serverAlias,
|
||||
sessionKey.getBytes(),
|
||||
sessionKey.getEType(),
|
||||
delegatedCred.getFlags(),
|
||||
delegatedCred.getAuthTime(),
|
||||
delegatedCred.getStartTime(),
|
||||
delegatedCred.getEndTime(),
|
||||
delegatedCred.getRenewTill(),
|
||||
delegatedCred.getClientAddresses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final GSSNameSpi getName() throws GSSException {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException {
|
||||
Date d = getEndTime();
|
||||
if (d == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long retVal = d.getTime() - System.currentTimeMillis();
|
||||
return (int)(retVal/1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sun.security.krb5.Credentials instance so that it maybe
|
||||
* used in that package for th Kerberos protocol.
|
||||
*/
|
||||
Credentials getKrb5Credentials() {
|
||||
return krb5Credentials;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Call to this.refresh() should refresh the locally cached copy
|
||||
* of krb5Credentials also.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element.
|
||||
*/
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
destroy();
|
||||
} catch (javax.security.auth.DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX call to this.destroy() should destroy the locally cached copy
|
||||
// of krb5Credentials and then call super.destroy().
|
||||
|
||||
private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name,
|
||||
int initLifetime)
|
||||
throws GSSException {
|
||||
|
||||
final String clientPrincipal;
|
||||
|
||||
/*
|
||||
* Find the TGT for the realm that the client is in. If the client
|
||||
* name is not available, then use the default realm.
|
||||
*/
|
||||
if (name != null) {
|
||||
clientPrincipal = (name.getKrb5PrincipalName()).getName();
|
||||
} else {
|
||||
clientPrincipal = null;
|
||||
}
|
||||
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
try {
|
||||
final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN)
|
||||
? GSSCaller.CALLER_INITIATE
|
||||
: caller;
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<KerberosTicket>() {
|
||||
public KerberosTicket run() throws Exception {
|
||||
// It's OK to use null as serverPrincipal. TGT is almost
|
||||
// the first ticket for a principal and we use list.
|
||||
return Krb5Util.getInitialTicket(
|
||||
realCaller,
|
||||
clientPrincipal, acc);
|
||||
}});
|
||||
} catch (PrivilegedActionException e) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.NO_CRED, -1,
|
||||
"Attempt to obtain new INITIATE credentials failed!" +
|
||||
" (" + e.getMessage() + ")");
|
||||
ge.initCause(e.getException());
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
try {
|
||||
Krb5NameElement kname = (Krb5NameElement)name;
|
||||
Credentials newCred = Credentials.acquireS4U2selfCreds(
|
||||
kname.getKrb5PrincipalName(), krb5Credentials);
|
||||
return new Krb5ProxyCredential(this, kname, newCred.getTicket());
|
||||
} catch (IOException | KrbException ke) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Attempt to obtain S4U2self credentials failed!");
|
||||
ge.initCause(ke);
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
}
|
||||
234
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5MechFactory.java
Normal file
234
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5MechFactory.java
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Krb5 Mechanism plug in for JGSS
|
||||
* This is the properties object required by the JGSS framework.
|
||||
* All mechanism specific information is defined here.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public final class Krb5MechFactory implements MechanismFactory {
|
||||
|
||||
private static final boolean DEBUG = Krb5Util.DEBUG;
|
||||
|
||||
static final Provider PROVIDER =
|
||||
new sun.security.jgss.SunProvider();
|
||||
|
||||
static final Oid GSS_KRB5_MECH_OID =
|
||||
createOid("1.2.840.113554.1.2.2");
|
||||
|
||||
static final Oid NT_GSS_KRB5_PRINCIPAL =
|
||||
createOid("1.2.840.113554.1.2.2.1");
|
||||
|
||||
private static Oid[] nameTypes =
|
||||
new Oid[] { GSSName.NT_USER_NAME,
|
||||
GSSName.NT_HOSTBASED_SERVICE,
|
||||
GSSName.NT_EXPORT_NAME,
|
||||
NT_GSS_KRB5_PRINCIPAL};
|
||||
|
||||
final private GSSCaller caller;
|
||||
|
||||
private static Krb5CredElement getCredFromSubject(GSSNameSpi name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Vector<Krb5CredElement> creds =
|
||||
GSSUtil.searchSubject(name, GSS_KRB5_MECH_OID, initiate,
|
||||
(initiate ?
|
||||
Krb5InitCredential.class :
|
||||
Krb5AcceptCredential.class));
|
||||
|
||||
Krb5CredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
if (initiate) {
|
||||
checkInitCredPermission((Krb5NameElement) result.getName());
|
||||
} else {
|
||||
checkAcceptCredPermission
|
||||
((Krb5NameElement) result.getName(), name);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Krb5MechFactory(GSSCaller caller) {
|
||||
this.caller = caller;
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return Krb5NameElement.getInstance(nameStr, nameType);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
// At this point, even an exported name is stripped down to safe
|
||||
// bytes only
|
||||
// XXX Use encoding here
|
||||
return Krb5NameElement.getInstance(new String(name), nameType);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime,
|
||||
int usage) throws GSSException {
|
||||
|
||||
if (name != null && !(name instanceof Krb5NameElement)) {
|
||||
name = Krb5NameElement.getInstance(name.toString(),
|
||||
name.getStringNameType());
|
||||
}
|
||||
|
||||
Krb5CredElement credElement = getCredFromSubject
|
||||
(name, (usage != GSSCredential.ACCEPT_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
if (usage == GSSCredential.INITIATE_ONLY ||
|
||||
usage == GSSCredential.INITIATE_AND_ACCEPT) {
|
||||
credElement = Krb5InitCredential.getInstance
|
||||
(caller, (Krb5NameElement) name, initLifetime);
|
||||
credElement = Krb5ProxyCredential.tryImpersonation(
|
||||
caller, (Krb5InitCredential)credElement);
|
||||
checkInitCredPermission
|
||||
((Krb5NameElement) credElement.getName());
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
credElement =
|
||||
Krb5AcceptCredential.getInstance(caller,
|
||||
(Krb5NameElement) name);
|
||||
checkAcceptCredPermission
|
||||
((Krb5NameElement) credElement.getName(), name);
|
||||
} else
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unknown usage mode requested");
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public static void checkInitCredPermission(Krb5NameElement name) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
String realm = (name.getKrb5PrincipalName()).getRealmAsString();
|
||||
String tgsPrincipal =
|
||||
new String("krbtgt/" + realm + '@' + realm);
|
||||
ServicePermission perm =
|
||||
new ServicePermission(tgsPrincipal, "initiate");
|
||||
try {
|
||||
sm.checkPermission(perm);
|
||||
} catch (SecurityException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Permission to initiate" +
|
||||
"kerberos init credential" + e.getMessage());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkAcceptCredPermission(Krb5NameElement name,
|
||||
GSSNameSpi originalName) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null && name != null) {
|
||||
ServicePermission perm = new ServicePermission
|
||||
(name.getKrb5PrincipalName().getName(), "accept");
|
||||
try {
|
||||
sm.checkPermission(perm);
|
||||
} catch (SecurityException e) {
|
||||
if (originalName == null) {
|
||||
// Don't disclose the name of the principal
|
||||
e = new SecurityException("No permission to acquire "
|
||||
+ "Kerberos accept credential");
|
||||
// Don't call e.initCause() with caught exception
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred, int lifetime)
|
||||
throws GSSException {
|
||||
if (peer != null && !(peer instanceof Krb5NameElement)) {
|
||||
peer = Krb5NameElement.getInstance(peer.toString(),
|
||||
peer.getStringNameType());
|
||||
}
|
||||
// XXX Convert myInitiatorCred to Krb5CredElement
|
||||
if (myInitiatorCred == null) {
|
||||
myInitiatorCred = getCredentialElement(null, lifetime, 0,
|
||||
GSSCredential.INITIATE_ONLY);
|
||||
}
|
||||
return new Krb5Context(caller, (Krb5NameElement)peer,
|
||||
(Krb5CredElement)myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException {
|
||||
// XXX Convert myAcceptorCred to Krb5CredElement
|
||||
if (myAcceptorCred == null) {
|
||||
myAcceptorCred = getCredentialElement(null, 0,
|
||||
GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
|
||||
}
|
||||
return new Krb5Context(caller, (Krb5CredElement)myAcceptorCred);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
return new Krb5Context(caller, exportedContext);
|
||||
}
|
||||
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return PROVIDER;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() {
|
||||
// nameTypes is cloned in GSSManager.getNamesForMech
|
||||
return nameTypes;
|
||||
}
|
||||
|
||||
private static Oid createOid(String oidStr) {
|
||||
Oid retVal = null;
|
||||
try {
|
||||
retVal = new Oid(oidStr);
|
||||
} catch (GSSException e) {
|
||||
// Should not happen!
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
348
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5NameElement.java
Normal file
348
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5NameElement.java
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
import sun.security.krb5.Realm;
|
||||
import sun.security.krb5.KrbException;
|
||||
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.Provider;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Implements the GSSNameSpi for the krb5 mechanism.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
public class Krb5NameElement
|
||||
implements GSSNameSpi {
|
||||
|
||||
private PrincipalName krb5PrincipalName;
|
||||
|
||||
private String gssNameStr = null;
|
||||
private Oid gssNameType = null;
|
||||
|
||||
// XXX Move this concept into PrincipalName's asn1Encode() sometime
|
||||
private static String CHAR_ENCODING = "UTF-8";
|
||||
|
||||
private Krb5NameElement(PrincipalName principalName,
|
||||
String gssNameStr,
|
||||
Oid gssNameType) {
|
||||
this.krb5PrincipalName = principalName;
|
||||
this.gssNameStr = gssNameStr;
|
||||
this.gssNameType = gssNameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Krb5NameElement object. Internally it stores the
|
||||
* information provided by the input parameters so that they may later
|
||||
* be used for output when a printable representaion of this name is
|
||||
* needed in GSS-API format rather than in Kerberos format.
|
||||
*
|
||||
*/
|
||||
static Krb5NameElement getInstance(String gssNameStr, Oid gssNameType)
|
||||
throws GSSException {
|
||||
|
||||
/*
|
||||
* A null gssNameType implies that the mechanism default
|
||||
* Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL be used.
|
||||
*/
|
||||
if (gssNameType == null)
|
||||
gssNameType = Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL;
|
||||
else
|
||||
if (!gssNameType.equals(GSSName.NT_USER_NAME) &&
|
||||
!gssNameType.equals(GSSName.NT_HOSTBASED_SERVICE) &&
|
||||
!gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL) &&
|
||||
!gssNameType.equals(GSSName.NT_EXPORT_NAME))
|
||||
throw new GSSException(GSSException.BAD_NAMETYPE, -1,
|
||||
gssNameType.toString()
|
||||
+" is an unsupported nametype");
|
||||
|
||||
PrincipalName principalName;
|
||||
try {
|
||||
|
||||
if (gssNameType.equals(GSSName.NT_EXPORT_NAME) ||
|
||||
gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL)) {
|
||||
principalName = new PrincipalName(gssNameStr,
|
||||
PrincipalName.KRB_NT_PRINCIPAL);
|
||||
} else {
|
||||
|
||||
String[] components = getComponents(gssNameStr);
|
||||
|
||||
/*
|
||||
* We have forms of GSS name strings that can come in:
|
||||
*
|
||||
* 1. names of the form "foo" with just one
|
||||
* component. (This might include a "@" but only in escaped
|
||||
* form like "\@")
|
||||
* 2. names of the form "foo@bar" with two components
|
||||
*
|
||||
* The nametypes that are accepted are NT_USER_NAME, and
|
||||
* NT_HOSTBASED_SERVICE.
|
||||
*/
|
||||
|
||||
if (gssNameType.equals(GSSName.NT_USER_NAME))
|
||||
principalName = new PrincipalName(gssNameStr,
|
||||
PrincipalName.KRB_NT_PRINCIPAL);
|
||||
else {
|
||||
String hostName = null;
|
||||
String service = components[0];
|
||||
if (components.length >= 2)
|
||||
hostName = components[1];
|
||||
|
||||
String principal = getHostBasedInstance(service, hostName);
|
||||
principalName = new PrincipalName(principal,
|
||||
PrincipalName.KRB_NT_SRV_HST);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (KrbException e) {
|
||||
throw new GSSException(GSSException.BAD_NAME, -1, e.getMessage());
|
||||
}
|
||||
|
||||
if (principalName.isRealmDeduced() && !Realm.AUTODEDUCEREALM) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkPermission(new ServicePermission(
|
||||
"@" + principalName.getRealmAsString(), "-"));
|
||||
} catch (SecurityException se) {
|
||||
// Do not chain the actual exception to hide info
|
||||
throw new GSSException(GSSException.FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Krb5NameElement(principalName, gssNameStr, gssNameType);
|
||||
}
|
||||
|
||||
public static Krb5NameElement getInstance(PrincipalName principalName) {
|
||||
return new Krb5NameElement(principalName,
|
||||
principalName.getName(),
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
|
||||
private static String[] getComponents(String gssNameStr)
|
||||
throws GSSException {
|
||||
|
||||
String[] retVal;
|
||||
|
||||
// XXX Perhaps provide this parsing code in PrincipalName
|
||||
|
||||
// Look for @ as in service@host
|
||||
// Assumes host name will not have an escaped '@'
|
||||
int separatorPos = gssNameStr.lastIndexOf('@', gssNameStr.length());
|
||||
|
||||
// Not really a separator if it is escaped. Then this is just part
|
||||
// of the principal name or service name
|
||||
if ((separatorPos > 0) &&
|
||||
(gssNameStr.charAt(separatorPos-1) == '\\')) {
|
||||
// Is the `\` character escaped itself?
|
||||
if ((separatorPos - 2 < 0) ||
|
||||
(gssNameStr.charAt(separatorPos-2) != '\\'))
|
||||
separatorPos = -1;
|
||||
}
|
||||
|
||||
if (separatorPos > 0) {
|
||||
String serviceName = gssNameStr.substring(0, separatorPos);
|
||||
String hostName = gssNameStr.substring(separatorPos+1);
|
||||
retVal = new String[] { serviceName, hostName};
|
||||
} else {
|
||||
retVal = new String[] {gssNameStr};
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
private static String getHostBasedInstance(String serviceName,
|
||||
String hostName)
|
||||
throws GSSException {
|
||||
StringBuffer temp = new StringBuffer(serviceName);
|
||||
|
||||
try {
|
||||
// A lack of "@" defaults to the service being on the local
|
||||
// host as per RFC 2743
|
||||
// XXX Move this part into JGSS framework
|
||||
if (hostName == null)
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
// use hostname as it is
|
||||
}
|
||||
hostName = hostName.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
temp = temp.append('/').append(hostName);
|
||||
return temp.toString();
|
||||
}
|
||||
|
||||
public final PrincipalName getKrb5PrincipalName() {
|
||||
return krb5PrincipalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal method for the GSSNameSpi objects.
|
||||
* If either name denotes an anonymous principal, the call should
|
||||
* return false.
|
||||
*
|
||||
* @param other to be compared with
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @exception GSSException with major codes of BAD_NAMETYPE,
|
||||
* BAD_NAME, FAILURE
|
||||
*/
|
||||
public boolean equals(GSSNameSpi other) throws GSSException {
|
||||
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
if (other instanceof Krb5NameElement) {
|
||||
Krb5NameElement that = (Krb5NameElement) other;
|
||||
return (this.krb5PrincipalName.getName().equals(
|
||||
that.krb5PrincipalName.getName()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this <code>GSSNameSpi</code> object to another Object
|
||||
* that might be a <code>GSSNameSpi</code>. The behaviour is exactly
|
||||
* the same as in {@link #equals(GSSNameSpi) equals} except that
|
||||
* no GSSException is thrown; instead, false will be returned in the
|
||||
* situation where an error occurs.
|
||||
*
|
||||
* @param another the object to be compared to
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @see #equals(GSSNameSpi)
|
||||
*/
|
||||
public boolean equals(Object another) {
|
||||
if (this == another) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (another instanceof Krb5NameElement)
|
||||
return equals((Krb5NameElement) another);
|
||||
} catch (GSSException e) {
|
||||
// ignore exception
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSNameSpi.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
return 37 * 17 + krb5PrincipalName.getName().hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the principal name in the form user@REALM or
|
||||
* host/service@REALM but with the following constraints that are
|
||||
* imposed by RFC 1964:
|
||||
* <pre>
|
||||
* (1) all occurrences of the characters `@`, `/`, and `\` within
|
||||
* principal components or realm names shall be quoted with an
|
||||
* immediately-preceding `\`.
|
||||
*
|
||||
* (2) all occurrences of the null, backspace, tab, or newline
|
||||
* characters within principal components or realm names will be
|
||||
* represented, respectively, with `\0`, `\b`, `\t`, or `\n`.
|
||||
*
|
||||
* (3) the `\` quoting character shall not be emitted within an
|
||||
* exported name except to accommodate cases (1) and (2).
|
||||
* </pre>
|
||||
*/
|
||||
public byte[] export() throws GSSException {
|
||||
// XXX Apply the above constraints.
|
||||
byte[] retVal = null;
|
||||
try {
|
||||
retVal = krb5PrincipalName.getName().getBytes(CHAR_ENCODING);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Can't happen
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mechanism type that this NameElement corresponds to.
|
||||
*
|
||||
* @return the Oid of the mechanism type
|
||||
*/
|
||||
public Oid getMechanism() {
|
||||
return (Krb5MechFactory.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation for this name. The printed
|
||||
* name type can be obtained by calling getStringNameType().
|
||||
*
|
||||
* @return string form of this name
|
||||
* @see #getStringNameType()
|
||||
* @overrides Object#toString
|
||||
*/
|
||||
public String toString() {
|
||||
return (gssNameStr);
|
||||
// For testing: return (super.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name type oid.
|
||||
*/
|
||||
public Oid getGSSNameType() {
|
||||
return (gssNameType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid describing the format of the printable name.
|
||||
*
|
||||
* @return the Oid for the format of the printed name
|
||||
*/
|
||||
public Oid getStringNameType() {
|
||||
// XXX For NT_EXPORT_NAME return a different name type. Infact,
|
||||
// don't even store NT_EXPORT_NAME in the cons.
|
||||
return (gssNameType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this name object represents an Anonymous name.
|
||||
*/
|
||||
public boolean isAnonymousName() {
|
||||
return (gssNameType.equals(GSSName.NT_ANONYMOUS));
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5ProxyCredential.java
Normal file
142
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5ProxyCredential.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.KrbException;
|
||||
import sun.security.krb5.internal.Ticket;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
|
||||
/**
|
||||
* Implements the krb5 proxy credential element used in constrained
|
||||
* delegation. It is used in both impersonation (where there is no Kerberos 5
|
||||
* communication between the middle server and the client) and normal
|
||||
* constrained delegation (where there is, but client has not called
|
||||
* requestCredDeleg(true)).
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
public class Krb5ProxyCredential
|
||||
implements Krb5CredElement {
|
||||
|
||||
public final Krb5InitCredential self; // the middle server
|
||||
private final Krb5NameElement client; // the client
|
||||
|
||||
// The ticket with cname=client and sname=self. This can be a normal
|
||||
// service ticket or an S4U2self ticket.
|
||||
public final Ticket tkt;
|
||||
|
||||
Krb5ProxyCredential(Krb5InitCredential self, Krb5NameElement client,
|
||||
Ticket tkt) {
|
||||
this.self = self;
|
||||
this.tkt = tkt;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
// The client name behind the proxy
|
||||
@Override
|
||||
public final Krb5NameElement getName() throws GSSException {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInitLifetime() throws GSSException {
|
||||
// endTime of tkt is not used by KDC, and it's also not
|
||||
// available in the case of kerberos constr deleg
|
||||
return self.getInitLifetime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
self.destroy();
|
||||
} catch (javax.security.auth.DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
// Cannot impersonate multiple levels without the impersonatee's TGT.
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Only an initiate credentials can impersonate");
|
||||
}
|
||||
|
||||
// Try to see if a default credential should act as an impersonator.
|
||||
static Krb5CredElement tryImpersonation(GSSCaller caller,
|
||||
Krb5InitCredential initiator) throws GSSException {
|
||||
|
||||
try {
|
||||
KerberosTicket proxy = initiator.proxyTicket;
|
||||
if (proxy != null) {
|
||||
Credentials proxyCreds = Krb5Util.ticketToCreds(proxy);
|
||||
return new Krb5ProxyCredential(initiator,
|
||||
Krb5NameElement.getInstance(proxyCreds.getClient()),
|
||||
proxyCreds.getTicket());
|
||||
} else {
|
||||
return initiator;
|
||||
}
|
||||
} catch (KrbException | IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_CREDENTIAL, -1,
|
||||
"Cannot create proxy credential");
|
||||
}
|
||||
}
|
||||
}
|
||||
118
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Token.java
Normal file
118
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Token.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import java.io.IOException;
|
||||
import sun.security.util.*;
|
||||
import sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This class represents a base class for all Kerberos v5 GSS-API
|
||||
* tokens. It contains commonly used definitions and utilities.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
abstract class Krb5Token extends GSSToken {
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the initSecContext call
|
||||
* carrying the AP_REQ .
|
||||
*/
|
||||
public static final int AP_REQ_ID = 0x0100;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the acceptSecContext call
|
||||
* carrying the AP_REP .
|
||||
*/
|
||||
public static final int AP_REP_ID = 0x0200;
|
||||
|
||||
/**
|
||||
* The token id defined for any token carrying a KRB-ERR message.
|
||||
*/
|
||||
public static final int ERR_ID = 0x0300;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the getMIC call.
|
||||
*/
|
||||
public static final int MIC_ID = 0x0101;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the wrap call.
|
||||
*/
|
||||
public static final int WRAP_ID = 0x0201;
|
||||
|
||||
// new token ID draft-ietf-krb-wg-gssapi-cfx-07.txt
|
||||
public static final int MIC_ID_v2 = 0x0404;
|
||||
public static final int WRAP_ID_v2 = 0x0504;
|
||||
|
||||
/**
|
||||
* The object identifier corresponding to the Kerberos v5 GSS-API
|
||||
* mechanism.
|
||||
*/
|
||||
public static ObjectIdentifier OID;
|
||||
|
||||
static {
|
||||
try {
|
||||
OID = new ObjectIdentifier(Krb5MechFactory.
|
||||
GSS_KRB5_MECH_OID.toString());
|
||||
} catch (IOException ioe) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a strign representing the token type.
|
||||
*
|
||||
* @param tokenId the token id for which a string name is desired
|
||||
* @return the String name of this token type
|
||||
*/
|
||||
public static String getTokenName(int tokenId) {
|
||||
String retVal = null;
|
||||
switch (tokenId) {
|
||||
case AP_REQ_ID:
|
||||
case AP_REP_ID:
|
||||
retVal = "Context Establishment Token";
|
||||
break;
|
||||
case MIC_ID:
|
||||
retVal = "MIC Token";
|
||||
break;
|
||||
case MIC_ID_v2:
|
||||
retVal = "MIC Token (new format)";
|
||||
break;
|
||||
case WRAP_ID:
|
||||
retVal = "Wrap Token";
|
||||
break;
|
||||
case WRAP_ID_v2:
|
||||
retVal = "Wrap Token (new format)";
|
||||
break;
|
||||
default:
|
||||
retVal = "Kerberos GSS-API Mechanism Token";
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
319
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Util.java
Normal file
319
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Util.java
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.security.AccessControlContext;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.KrbException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import sun.security.krb5.KerberosSecrets;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
/**
|
||||
* Utilities for obtaining and converting Kerberos tickets.
|
||||
*
|
||||
*/
|
||||
public class Krb5Util {
|
||||
|
||||
static final boolean DEBUG =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction
|
||||
("sun.security.krb5.debug")).booleanValue();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private Krb5Util() { // Cannot create one of these
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the service ticket for serverPrincipal from caller's Subject
|
||||
* or from Subject obtained by logging in, or if not found, via the
|
||||
* Ticket Granting Service using the TGT obtained from the Subject.
|
||||
*
|
||||
* Caller must have permission to:
|
||||
* - access and update Subject's private credentials
|
||||
* - create LoginContext
|
||||
* - read the auth.login.defaultCallbackHandler security property
|
||||
*
|
||||
* NOTE: This method is used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static KerberosTicket getTicketFromSubjectAndTgs(GSSCaller caller,
|
||||
String clientPrincipal, String serverPrincipal, String tgsPrincipal,
|
||||
AccessControlContext acc)
|
||||
throws LoginException, KrbException, IOException {
|
||||
|
||||
// 1. Try to find service ticket in acc subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket = SubjectComber.find(accSubj,
|
||||
serverPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
|
||||
if (ticket != null) {
|
||||
return ticket; // found it
|
||||
}
|
||||
|
||||
Subject loginSubj = null;
|
||||
if (!GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
// 2. Try to get ticket from login
|
||||
try {
|
||||
loginSubj = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
ticket = SubjectComber.find(loginSubj,
|
||||
serverPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
if (ticket != null) {
|
||||
return ticket; // found it
|
||||
}
|
||||
} catch (LoginException e) {
|
||||
// No login entry to use
|
||||
// ignore and continue
|
||||
}
|
||||
}
|
||||
|
||||
// Service ticket not found in subject or login
|
||||
// Try to get TGT to acquire service ticket
|
||||
|
||||
// 3. Try to get TGT from acc subject
|
||||
KerberosTicket tgt = SubjectComber.find(accSubj,
|
||||
tgsPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
|
||||
boolean fromAcc;
|
||||
if (tgt == null && loginSubj != null) {
|
||||
// 4. Try to get TGT from login subject
|
||||
tgt = SubjectComber.find(loginSubj,
|
||||
tgsPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
fromAcc = false;
|
||||
} else {
|
||||
fromAcc = true;
|
||||
}
|
||||
|
||||
// 5. Try to get service ticket using TGT
|
||||
if (tgt != null) {
|
||||
Credentials tgtCreds = ticketToCreds(tgt);
|
||||
Credentials serviceCreds = Credentials.acquireServiceCreds(
|
||||
serverPrincipal, tgtCreds);
|
||||
if (serviceCreds != null) {
|
||||
ticket = credsToTicket(serviceCreds);
|
||||
|
||||
// Store service ticket in acc's Subject
|
||||
if (fromAcc && accSubj != null && !accSubj.isReadOnly()) {
|
||||
accSubj.getPrivateCredentials().add(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ticket corresponding to the client/server principal
|
||||
* pair from the Subject in the specified AccessControlContext.
|
||||
*/
|
||||
static KerberosTicket getServiceTicket(GSSCaller caller,
|
||||
String clientPrincipal, String serverPrincipal,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get ticket from acc's Subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket =
|
||||
SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
|
||||
KerberosTicket.class);
|
||||
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the initial TGT corresponding to the client principal
|
||||
* from the Subject in the specified AccessControlContext.
|
||||
* If the ticket can not be found in the Subject, and if
|
||||
* useSubjectCredsOnly is false, then obtain ticket from
|
||||
* a LoginContext.
|
||||
*/
|
||||
static KerberosTicket getInitialTicket(GSSCaller caller,
|
||||
String clientPrincipal,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get ticket from acc's Subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket =
|
||||
SubjectComber.find(accSubj, null, clientPrincipal,
|
||||
KerberosTicket.class);
|
||||
|
||||
// Try to get ticket from Subject obtained from GSSUtil
|
||||
if (ticket == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
ticket = SubjectComber.find(subject,
|
||||
null, clientPrincipal, KerberosTicket.class);
|
||||
}
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the caller's Subject, or Subject obtained by logging in
|
||||
* via the specified caller.
|
||||
*
|
||||
* Caller must have permission to:
|
||||
* - access the Subject
|
||||
* - create LoginContext
|
||||
* - read the auth.login.defaultCallbackHandler security property
|
||||
*
|
||||
* NOTE: This method is used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static Subject getSubject(GSSCaller caller,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get the Subject from acc
|
||||
Subject subject = Subject.getSubject(acc);
|
||||
|
||||
// Try to get Subject obtained from GSSUtil
|
||||
if (subject == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ServiceCreds for the specified server principal from
|
||||
* the Subject in the specified AccessControlContext. If not found, and if
|
||||
* useSubjectCredsOnly is false, then obtain from a LoginContext.
|
||||
*
|
||||
* NOTE: This method is also used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static ServiceCreds getServiceCreds(GSSCaller caller,
|
||||
String serverPrincipal, AccessControlContext acc)
|
||||
throws LoginException {
|
||||
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
ServiceCreds sc = null;
|
||||
if (accSubj != null) {
|
||||
sc = ServiceCreds.getInstance(accSubj, serverPrincipal);
|
||||
}
|
||||
if (sc == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
sc = ServiceCreds.getInstance(subject, serverPrincipal);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
public static KerberosTicket credsToTicket(Credentials serviceCreds) {
|
||||
EncryptionKey sessionKey = serviceCreds.getSessionKey();
|
||||
KerberosTicket kt = new KerberosTicket(
|
||||
serviceCreds.getEncoded(),
|
||||
new KerberosPrincipal(serviceCreds.getClient().getName()),
|
||||
new KerberosPrincipal(serviceCreds.getServer().getName(),
|
||||
KerberosPrincipal.KRB_NT_SRV_INST),
|
||||
sessionKey.getBytes(),
|
||||
sessionKey.getEType(),
|
||||
serviceCreds.getFlags(),
|
||||
serviceCreds.getAuthTime(),
|
||||
serviceCreds.getStartTime(),
|
||||
serviceCreds.getEndTime(),
|
||||
serviceCreds.getRenewTill(),
|
||||
serviceCreds.getClientAddresses());
|
||||
PrincipalName clientAlias = serviceCreds.getClientAlias();
|
||||
PrincipalName serverAlias = serviceCreds.getServerAlias();
|
||||
if (clientAlias != null) {
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(kt, new KerberosPrincipal(
|
||||
clientAlias.getName(), clientAlias.getNameType()));
|
||||
}
|
||||
if (serverAlias != null) {
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(kt, new KerberosPrincipal(
|
||||
serverAlias.getName(), serverAlias.getNameType()));
|
||||
}
|
||||
return kt;
|
||||
};
|
||||
|
||||
public static Credentials ticketToCreds(KerberosTicket kerbTicket)
|
||||
throws KrbException, IOException {
|
||||
KerberosPrincipal clientAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetClientAlias(kerbTicket);
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(kerbTicket);
|
||||
return new Credentials(
|
||||
kerbTicket.getEncoded(),
|
||||
kerbTicket.getClient().getName(),
|
||||
(clientAlias != null ? clientAlias.getName() : null),
|
||||
kerbTicket.getServer().getName(),
|
||||
(serverAlias != null ? serverAlias.getName() : null),
|
||||
kerbTicket.getSessionKey().getEncoded(),
|
||||
kerbTicket.getSessionKeyType(),
|
||||
kerbTicket.getFlags(),
|
||||
kerbTicket.getAuthTime(),
|
||||
kerbTicket.getStartTime(),
|
||||
kerbTicket.getEndTime(),
|
||||
kerbTicket.getRenewTill(),
|
||||
kerbTicket.getClientAddresses());
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to get a sun..KeyTab from a javax..KeyTab
|
||||
* @param ktab the javax..KeyTab object
|
||||
* @return the sun..KeyTab object
|
||||
*/
|
||||
public static sun.security.krb5.internal.ktab.KeyTab
|
||||
snapshotFromJavaxKeyTab(KeyTab ktab) {
|
||||
return KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.keyTabTakeSnapshot(ktab);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to get EncryptionKeys from a javax..KeyTab
|
||||
* @param ktab the javax..KeyTab object
|
||||
* @param cname the PrincipalName
|
||||
* @return the EKeys, never null, might be empty
|
||||
*/
|
||||
public static EncryptionKey[] keysFromJavaxKeyTab(
|
||||
KeyTab ktab, PrincipalName cname) {
|
||||
return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname);
|
||||
}
|
||||
|
||||
public static String keyInfo(byte[] data) {
|
||||
if (data == null) {
|
||||
return "null key";
|
||||
} else if (data.length == 0) {
|
||||
return "empty key";
|
||||
} else {
|
||||
for (byte b : data) {
|
||||
if (b != 0) {
|
||||
return data.length + "-byte key";
|
||||
}
|
||||
}
|
||||
return data.length + "-byte zero key";
|
||||
}
|
||||
}
|
||||
}
|
||||
721
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken.java
Normal file
721
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken.java
Normal file
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* This class is a base class for other token definitions that pertain to
|
||||
* per-message GSS-API calls. Conceptually GSS-API has two types of
|
||||
* per-message tokens: WrapToken and MicToken. They differ in the respect
|
||||
* that a WrapToken carries additional plaintext or ciphertext application
|
||||
* data besides just the sequence number and checksum. This class
|
||||
* encapsulates the commonality in the structure of the WrapToken and the
|
||||
* MicToken. This structure can be represented as:
|
||||
* <p>
|
||||
* <pre>
|
||||
* 0..1 TOK_ID Identification field.
|
||||
* 01 01 - Mic token
|
||||
* 02 01 - Wrap token
|
||||
* 2..3 SGN_ALG Checksum algorithm indicator.
|
||||
* 00 00 - DES MAC MD5
|
||||
* 01 00 - MD2.5
|
||||
* 02 00 - DES MAC
|
||||
* 04 00 - HMAC SHA1 DES3-KD
|
||||
* 11 00 - RC4-HMAC
|
||||
* 4..5 SEAL_ALG ff ff - none
|
||||
* 00 00 - DES
|
||||
* 02 00 - DES3-KD
|
||||
* 10 00 - RC4-HMAC
|
||||
* 6..7 Filler Contains ff ff
|
||||
* 8..15 SND_SEQ Encrypted sequence number field.
|
||||
* 16..s+15 SGN_CKSUM Checksum of plaintext padded data,
|
||||
* calculated according to algorithm
|
||||
* specified in SGN_ALG field.
|
||||
* s+16..last Data encrypted or plaintext padded data
|
||||
* </pre>
|
||||
* Where "s" indicates the size of the checksum.
|
||||
* <p>
|
||||
* As always, this is preceeded by a GSSHeader.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @author Ram Marti
|
||||
* @see sun.security.jgss.GSSHeader
|
||||
*/
|
||||
|
||||
abstract class MessageToken extends Krb5Token {
|
||||
/* Fields in header minus checksum size */
|
||||
private static final int TOKEN_NO_CKSUM_SIZE = 16;
|
||||
|
||||
/**
|
||||
* Filler data as defined in the specification of the Kerberos v5 GSS-API
|
||||
* Mechanism.
|
||||
*/
|
||||
private static final int FILLER = 0xffff;
|
||||
|
||||
// Signing algorithm values (for the SNG_ALG field)
|
||||
|
||||
// From RFC 1964
|
||||
/* Use a DES MAC MD5 checksum */
|
||||
static final int SGN_ALG_DES_MAC_MD5 = 0x0000;
|
||||
|
||||
/* Use DES MAC checksum. */
|
||||
static final int SGN_ALG_DES_MAC = 0x0200;
|
||||
|
||||
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
||||
/* Use a HMAC SHA1 DES3 -KD checksum */
|
||||
static final int SGN_ALG_HMAC_SHA1_DES3_KD = 0x0400;
|
||||
|
||||
// Sealing algorithm values (for the SEAL_ALG field)
|
||||
|
||||
// RFC 1964
|
||||
/**
|
||||
* A value for the SEAL_ALG field that indicates that no encryption was
|
||||
* used.
|
||||
*/
|
||||
static final int SEAL_ALG_NONE = 0xffff;
|
||||
/* Use DES CBC encryption algorithm. */
|
||||
static final int SEAL_ALG_DES = 0x0000;
|
||||
|
||||
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
||||
/**
|
||||
* Use DES3-KD sealing algorithm. (draft-raeburn-cat-gssapi-krb5-3des-00)
|
||||
* This algorithm uses triple-DES with key derivation, with a usage
|
||||
* value KG_USAGE_SEAL. Padding is still to 8-byte multiples, and the
|
||||
* IV for encrypting application data is zero.
|
||||
*/
|
||||
static final int SEAL_ALG_DES3_KD = 0x0200;
|
||||
|
||||
// draft draft-brezak-win2k-krb-rc4-hmac-04.txt
|
||||
static final int SEAL_ALG_ARCFOUR_HMAC = 0x1000;
|
||||
static final int SGN_ALG_HMAC_MD5_ARCFOUR = 0x1100;
|
||||
|
||||
private static final int TOKEN_ID_POS = 0;
|
||||
private static final int SIGN_ALG_POS = 2;
|
||||
private static final int SEAL_ALG_POS = 4;
|
||||
|
||||
private int seqNumber;
|
||||
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
|
||||
private int tokenId = 0;
|
||||
private GSSHeader gssHeader = null;
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
private byte[] checksum = null;
|
||||
private byte[] encSeqNumber = null;
|
||||
private byte[] seqNumberData = null;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from a byte array. If there are more bytes
|
||||
* in the array than needed, the extra bytes are simply ignroed.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param tokenBytes the byte array containing the token
|
||||
* @param tokenOffset the offset where the token begins
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem parsing the token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
this(tokenId, context,
|
||||
new ByteArrayInputStream(tokenBytes, tokenOffset, tokenLen),
|
||||
prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
||||
* demand and the thread might block if there are not enough bytes to
|
||||
* complete the token.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param is the InputStream from which to read
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem reading from the
|
||||
* InputStream or parsing the token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context, InputStream is,
|
||||
MessageProp prop) throws GSSException {
|
||||
init(tokenId, context);
|
||||
|
||||
try {
|
||||
gssHeader = new GSSHeader(is);
|
||||
|
||||
if (!gssHeader.getOid().equals((Object)OID)) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId));
|
||||
}
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
tokenHeader = new MessageTokenHeader(is, prop);
|
||||
|
||||
encSeqNumber = new byte[8];
|
||||
readFully(is, encSeqNumber);
|
||||
|
||||
// debug("\n\tRead EncSeq#=" +
|
||||
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
||||
|
||||
checksum = new byte[cipherHelper.getChecksumLength()];
|
||||
readFully(is, checksum);
|
||||
|
||||
// debug("\n\tRead checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
// debug("\nLeaving MessageToken.Cons\n");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the GSSHeader that was at the start of this
|
||||
* token.
|
||||
*/
|
||||
public final GSSHeader getGSSHeader() {
|
||||
return gssHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the token id that was contained in this token.
|
||||
* @return the token id in the token
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the encrypted sequence number in this token.
|
||||
* @return the encrypted sequence number in the token
|
||||
*/
|
||||
public final byte[] getEncSeqNumber() {
|
||||
return encSeqNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the checksum that was contained in this token.
|
||||
* @return the checksum in the token
|
||||
*/
|
||||
public final byte[] getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if this token contains any encrypted data.
|
||||
* @return true if it contains any encrypted data, false if there is only
|
||||
* plaintext data or if there is no data.
|
||||
*/
|
||||
public final boolean getConfState() {
|
||||
return confState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the checksum field and the encrypted sequence number
|
||||
* field. The encrypted sequence number uses the 8 bytes of the checksum
|
||||
* as an initial vector in a fixed DesCbc algorithm.
|
||||
*
|
||||
* @param prop the MessageProp structure that determines what sort of
|
||||
* checksum and sealing algorithm should be used. The lower byte
|
||||
* of qop determines the checksum algorithm while the upper byte
|
||||
* determines the signing algorithm.
|
||||
* Checksum values are:
|
||||
* 0 - default (DES_MAC)
|
||||
* 1 - MD5
|
||||
* 2 - DES_MD5
|
||||
* 3 - DES_MAC
|
||||
* 4 - HMAC_SHA1
|
||||
* Sealing values are:
|
||||
* 0 - default (DES)
|
||||
* 1 - DES
|
||||
* 2 - DES3-KD
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation
|
||||
*
|
||||
* @param data the application data to checksum
|
||||
* @param offset the offset where the data starts
|
||||
* @param len the length of the data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed
|
||||
* last during checksum calculation. e.g., padding that should be
|
||||
* appended to the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* encryption sequence number calculation.
|
||||
*/
|
||||
public void genSignAndSeqNumber(MessageProp prop,
|
||||
byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
|
||||
|
||||
int qop = prop.getQOP();
|
||||
if (qop != 0) {
|
||||
qop = 0;
|
||||
prop.setQOP(qop);
|
||||
}
|
||||
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// Create a token header with the correct sign and seal algorithm
|
||||
// values.
|
||||
tokenHeader =
|
||||
new MessageTokenHeader(tokenId, prop.getPrivacy(), qop);
|
||||
|
||||
// Calculate SGN_CKSUM
|
||||
|
||||
checksum =
|
||||
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
||||
|
||||
// debug("\n\tCalc checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
|
||||
// Calculate SND_SEQ
|
||||
|
||||
seqNumberData = new byte[8];
|
||||
|
||||
// When using this RC4 based encryption type, the sequence number is
|
||||
// always sent in big-endian rather than little-endian order.
|
||||
if (cipherHelper.isArcFour()) {
|
||||
writeBigEndian(seqNumber, seqNumberData);
|
||||
} else {
|
||||
// for all other etypes
|
||||
writeLittleEndian(seqNumber, seqNumberData);
|
||||
}
|
||||
if (!initiator) {
|
||||
seqNumberData[4] = (byte)0xff;
|
||||
seqNumberData[5] = (byte)0xff;
|
||||
seqNumberData[6] = (byte)0xff;
|
||||
seqNumberData[7] = (byte)0xff;
|
||||
}
|
||||
|
||||
encSeqNumber = cipherHelper.encryptSeq(checksum, seqNumberData, 0, 8);
|
||||
|
||||
// debug("\n\tCalc seqNum=" +
|
||||
// getHexBytes(seqNumberData, seqNumberData.length));
|
||||
// debug("\n\tCalc encSeqNum=" +
|
||||
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the checksum field and sequence number direction bytes
|
||||
* are valid and consistent with the application data.
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed last
|
||||
* during checksum calculation. e.g., padding that should be appended to
|
||||
* the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* encryption sequence number calculation.
|
||||
*/
|
||||
public final boolean verifySignAndSeqNumber(byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
// debug("\tIn verifySign:\n");
|
||||
|
||||
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
||||
|
||||
byte[] myChecksum =
|
||||
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
||||
|
||||
// debug("\t\tmychecksum: [" + getHexBytes(myChecksum) +"]\n");
|
||||
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
||||
|
||||
if (MessageDigest.isEqual(checksum, myChecksum)) {
|
||||
|
||||
seqNumberData = cipherHelper.decryptSeq(
|
||||
checksum, encSeqNumber, 0, 8);
|
||||
|
||||
// debug("\t\tencSeqNumber: [" + getHexBytes(encSeqNumber)
|
||||
// + "]\n");
|
||||
// debug("\t\tseqNumberData: [" + getHexBytes(seqNumberData)
|
||||
// + "]\n");
|
||||
|
||||
/*
|
||||
* The token from the initiator has direction bytes 0x00 and
|
||||
* the token from the acceptor has direction bytes 0xff.
|
||||
*/
|
||||
byte directionByte = 0;
|
||||
if (initiator)
|
||||
directionByte = (byte) 0xff; // Received token from acceptor
|
||||
|
||||
if ((seqNumberData[4] == directionByte) &&
|
||||
(seqNumberData[5] == directionByte) &&
|
||||
(seqNumberData[6] == directionByte) &&
|
||||
(seqNumberData[7] == directionByte))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public final int getSequenceNumber() {
|
||||
int sequenceNum = 0;
|
||||
if (cipherHelper.isArcFour()) {
|
||||
sequenceNum = readBigEndian(seqNumberData, 0, 4);
|
||||
} else {
|
||||
sequenceNum = readLittleEndian(seqNumberData, 0, 4);
|
||||
}
|
||||
return sequenceNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the checksum based on the algorithm stored in the
|
||||
* tokenHeader.
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed last
|
||||
* during checksum calculation. e.g., padding that should be appended to
|
||||
* the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation.
|
||||
*/
|
||||
private byte[] getChecksum(byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Will do getChecksum:\n");
|
||||
|
||||
/*
|
||||
* For checksum calculation the token header bytes i.e., the first 8
|
||||
* bytes following the GSSHeader, are logically prepended to the
|
||||
* application data to bind the data to this particular token.
|
||||
*
|
||||
* Note: There is no such requirement wrt adding padding to the
|
||||
* application data for checksumming, although the cryptographic
|
||||
* algorithm used might itself apply some padding.
|
||||
*/
|
||||
|
||||
byte[] tokenHeaderBytes = tokenHeader.getBytes();
|
||||
byte[] existingHeader = optionalHeader;
|
||||
byte[] checksumDataHeader = tokenHeaderBytes;
|
||||
|
||||
if (existingHeader != null) {
|
||||
checksumDataHeader = new byte[tokenHeaderBytes.length +
|
||||
existingHeader.length];
|
||||
System.arraycopy(tokenHeaderBytes, 0,
|
||||
checksumDataHeader, 0, tokenHeaderBytes.length);
|
||||
System.arraycopy(existingHeader, 0,
|
||||
checksumDataHeader, tokenHeaderBytes.length,
|
||||
existingHeader.length);
|
||||
}
|
||||
|
||||
return cipherHelper.calculateChecksum(tokenHeader.getSignAlg(),
|
||||
checksumDataHeader, optionalTrailer, data, offset, len, tokenId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an empty MessageToken for the local context to send to
|
||||
* the peer. It also increments the local sequence number in the
|
||||
* Krb5Context instance it uses after obtaining the object lock for
|
||||
* it.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token
|
||||
* @param context the Kerberos context associated with this token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context) throws GSSException {
|
||||
/*
|
||||
debug("\n============================");
|
||||
debug("\nMySessionKey=" +
|
||||
getHexBytes(context.getMySessionKey().getBytes()));
|
||||
debug("\nPeerSessionKey=" +
|
||||
getHexBytes(context.getPeerSessionKey().getBytes()));
|
||||
debug("\n============================\n");
|
||||
*/
|
||||
init(tokenId, context);
|
||||
this.seqNumber = context.incrementMySequenceNumber();
|
||||
}
|
||||
|
||||
private void init(int tokenId, Krb5Context context) throws GSSException {
|
||||
this.tokenId = tokenId;
|
||||
// Just for consistency check in Wrap
|
||||
this.confState = context.getConfState();
|
||||
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
this.cipherHelper = context.getCipherHelper(null);
|
||||
// debug("In MessageToken.Cons");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a GSSHeader and this token onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws GSSException if an error occurs while writing to the OutputStream
|
||||
*/
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
gssHeader = new GSSHeader(OID, getKrb5TokenSize());
|
||||
gssHeader.encode(os);
|
||||
tokenHeader.encode(os);
|
||||
// debug("Writing seqNumber: " + getHexBytes(encSeqNumber));
|
||||
os.write(encSeqNumber);
|
||||
// debug("Writing checksum: " + getHexBytes(checksum));
|
||||
os.write(checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the size of this token. Note that this excludes the size of
|
||||
* the GSSHeader.
|
||||
* @return token size
|
||||
*/
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return getTokenSize();
|
||||
}
|
||||
|
||||
protected final int getTokenSize() throws GSSException {
|
||||
return TOKEN_NO_CKSUM_SIZE + cipherHelper.getChecksumLength();
|
||||
}
|
||||
|
||||
protected static final int getTokenSize(CipherHelper ch)
|
||||
throws GSSException {
|
||||
return TOKEN_NO_CKSUM_SIZE + ch.getChecksumLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the conext key that is associated with this token.
|
||||
* @return the context key
|
||||
*/
|
||||
/*
|
||||
public final byte[] getContextKey() {
|
||||
return contextKey;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtains the encryption algorithm that should be used in this token
|
||||
* given the state of confidentiality the application requested.
|
||||
* Requested qop must be consistent with negotiated session key.
|
||||
* @param confRequested true if the application desired confidentiality
|
||||
* on this token, false otherwise
|
||||
* @param qop the qop requested by the application
|
||||
* @throws GSSException if qop is incompatible with the negotiated
|
||||
* session key
|
||||
*/
|
||||
protected abstract int getSealAlg(boolean confRequested, int qop)
|
||||
throws GSSException;
|
||||
|
||||
// ******************************************* //
|
||||
// I N N E R C L A S S E S F O L L O W
|
||||
// ******************************************* //
|
||||
|
||||
/**
|
||||
* This inner class represents the initial portion of the message token
|
||||
* and contains information about the checksum and encryption algorithms
|
||||
* that are in use. It constitutes the first 8 bytes of the
|
||||
* message token:
|
||||
* <pre>
|
||||
* 0..1 TOK_ID Identification field.
|
||||
* 01 01 - Mic token
|
||||
* 02 01 - Wrap token
|
||||
* 2..3 SGN_ALG Checksum algorithm indicator.
|
||||
* 00 00 - DES MAC MD5
|
||||
* 01 00 - MD2.5
|
||||
* 02 00 - DES MAC
|
||||
* 04 00 - HMAC SHA1 DES3-KD
|
||||
* 11 00 - RC4-HMAC
|
||||
* 4..5 SEAL_ALG ff ff - none
|
||||
* 00 00 - DES
|
||||
* 02 00 - DES3-KD
|
||||
* 10 00 - RC4-HMAC
|
||||
* 6..7 Filler Contains ff ff
|
||||
* </pre>
|
||||
*/
|
||||
class MessageTokenHeader {
|
||||
|
||||
private int tokenId;
|
||||
private int signAlg;
|
||||
private int sealAlg;
|
||||
|
||||
private byte[] bytes = new byte[8];
|
||||
|
||||
/**
|
||||
* Constructs a MessageTokenHeader for the specified token type with
|
||||
* appropriate checksum and encryption algorithms fields.
|
||||
*
|
||||
* @param tokenId the token id for this message token
|
||||
* @param conf true if confidentiality will be resuested with this
|
||||
* message token, false otherwise.
|
||||
* @param qop the value of the quality of protection that will be
|
||||
* desired.
|
||||
*/
|
||||
public MessageTokenHeader(int tokenId, boolean conf, int qop)
|
||||
throws GSSException {
|
||||
|
||||
this.tokenId = tokenId;
|
||||
|
||||
signAlg = MessageToken.this.getSgnAlg(qop);
|
||||
|
||||
sealAlg = MessageToken.this.getSealAlg(conf, qop);
|
||||
|
||||
bytes[0] = (byte) (tokenId >>> 8);
|
||||
bytes[1] = (byte) (tokenId);
|
||||
|
||||
bytes[2] = (byte) (signAlg >>> 8);
|
||||
bytes[3] = (byte) (signAlg);
|
||||
|
||||
bytes[4] = (byte) (sealAlg >>> 8);
|
||||
bytes[5] = (byte) (sealAlg);
|
||||
|
||||
bytes[6] = (byte) (MessageToken.FILLER >>> 8);
|
||||
bytes[7] = (byte) (MessageToken.FILLER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageTokenHeader by reading it from an InputStream
|
||||
* and sets the appropriate confidentiality and quality of protection
|
||||
* values in a MessageProp structure.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param prop the MessageProp to populate
|
||||
* @throws IOException is an error occurs while reading from the
|
||||
* InputStream
|
||||
*/
|
||||
public MessageTokenHeader(InputStream is, MessageProp prop)
|
||||
throws IOException {
|
||||
readFully(is, bytes);
|
||||
tokenId = readInt(bytes, TOKEN_ID_POS);
|
||||
signAlg = readInt(bytes, SIGN_ALG_POS);
|
||||
sealAlg = readInt(bytes, SEAL_ALG_POS);
|
||||
// debug("\nMessageTokenHeader read tokenId=" +
|
||||
// getHexBytes(bytes) + "\n");
|
||||
// XXX compare to FILLER
|
||||
int temp = readInt(bytes, SEAL_ALG_POS + 2);
|
||||
|
||||
// debug("SIGN_ALG=" + signAlg);
|
||||
|
||||
switch (sealAlg) {
|
||||
case SEAL_ALG_DES:
|
||||
case SEAL_ALG_DES3_KD:
|
||||
case SEAL_ALG_ARCFOUR_HMAC:
|
||||
prop.setPrivacy(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
prop.setQOP(0); // default
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this MessageTokenHeader onto an OutputStream
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException is an error occurs while writing
|
||||
*/
|
||||
public final void encode(OutputStream os) throws IOException {
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the token id for the message token.
|
||||
* @return the token id
|
||||
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID
|
||||
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sign algorithm for the message token.
|
||||
* @return the sign algorithm
|
||||
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC
|
||||
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC_MD5
|
||||
*/
|
||||
public final int getSignAlg() {
|
||||
return signAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seal algorithm for the message token.
|
||||
* @return the seal algorithm
|
||||
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_DES
|
||||
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_NONE
|
||||
*/
|
||||
public final int getSealAlg() {
|
||||
return sealAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes of this header.
|
||||
* @return 8 bytes that form this header
|
||||
*/
|
||||
public final byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
} // end of class MessageTokenHeader
|
||||
|
||||
|
||||
/**
|
||||
* Determine signing algorithm based on QOP.
|
||||
*/
|
||||
protected int getSgnAlg(int qop) throws GSSException {
|
||||
// QOP ignored
|
||||
return cipherHelper.getSgnAlg();
|
||||
}
|
||||
}
|
||||
643
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken_v2.java
Normal file
643
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken_v2.java
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class is a base class for new GSS token definitions, as defined
|
||||
* in RFC 4121, that pertain to per-message GSS-API calls. Conceptually
|
||||
* GSS-API has two types of per-message tokens: WrapToken and MicToken.
|
||||
* They differ in the respect that a WrapToken carries additional plaintext
|
||||
* or ciphertext application data besides just the sequence number and
|
||||
* checksum. This class encapsulates the commonality in the structure of
|
||||
* the WrapToken and the MicToken. This structure can be represented as:
|
||||
* <p>
|
||||
* <pre>
|
||||
* Wrap Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* ---------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_Wrap() contain the hex value 05 04
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3 Filler Contains the hex value FF.
|
||||
* 4..5 EC Contains the "extra count" field, in big-
|
||||
* endian order as described in section 4.2.3.
|
||||
* 6..7 RRC Contains the "right rotation count" in big
|
||||
* endian order, as described in section 4.2.5.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big-endian order.
|
||||
* 16..last Data Encrypted data for Wrap tokens with
|
||||
* confidentiality, or plaintext data followed
|
||||
* by the checksum for Wrap tokens without
|
||||
* confidentiality, as described in section
|
||||
* 4.2.4.
|
||||
* MIC Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* -----------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_GetMIC() contain the hex value 04 04
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3..7 Filler Contains five octets of hex value FF.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big-endian order.
|
||||
* 16..last SGN_CKSUM Checksum of the "to-be-signed" data and
|
||||
* octet 0..15, as described in section 4.2.4.
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* This class is the super class of WrapToken_v2 and MicToken_v2. The token's
|
||||
* header (bytes[0..15]) and data (byte[16..]) are saved in tokenHeader and
|
||||
* tokenData fields. Since there is no easy way to find out the exact length
|
||||
* of a WrapToken_v2 token from any header info, in the case of reading from
|
||||
* stream, we read all available() bytes into the token.
|
||||
* <p>
|
||||
* All read actions are performed in this super class. On the write part, the
|
||||
* super class only write the tokenHeader, and the content writing is inside
|
||||
* child classes.
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
|
||||
abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
protected static final int TOKEN_HEADER_SIZE = 16;
|
||||
private static final int TOKEN_ID_POS = 0;
|
||||
private static final int TOKEN_FLAG_POS = 2;
|
||||
private static final int TOKEN_EC_POS = 4;
|
||||
private static final int TOKEN_RRC_POS = 6;
|
||||
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
protected static final int CONFOUNDER_SIZE = 16;
|
||||
|
||||
// RFC 4121, key usage values
|
||||
static final int KG_USAGE_ACCEPTOR_SEAL = 22;
|
||||
static final int KG_USAGE_ACCEPTOR_SIGN = 23;
|
||||
static final int KG_USAGE_INITIATOR_SEAL = 24;
|
||||
static final int KG_USAGE_INITIATOR_SIGN = 25;
|
||||
|
||||
// RFC 4121, Flags Field
|
||||
private static final int FLAG_SENDER_IS_ACCEPTOR = 1;
|
||||
private static final int FLAG_WRAP_CONFIDENTIAL = 2;
|
||||
private static final int FLAG_ACCEPTOR_SUBKEY = 4;
|
||||
private static final int FILLER = 0xff;
|
||||
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
|
||||
// Common field
|
||||
private int tokenId = 0;
|
||||
private int seqNumber;
|
||||
protected byte[] tokenData; // content of token, without the header
|
||||
protected int tokenDataLen;
|
||||
|
||||
// Key usage number for crypto action
|
||||
private int key_usage = 0;
|
||||
|
||||
// EC and RRC fields, WrapToken only
|
||||
private int ec = 0;
|
||||
private int rrc = 0;
|
||||
|
||||
// Checksum. Always in MicToken, might be in WrapToken
|
||||
byte[] checksum = null;
|
||||
|
||||
// Context properties
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
private boolean have_acceptor_subkey = false;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from a byte array.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param tokenBytes the byte array containing the token
|
||||
* @param tokenOffset the offset where the token begins
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem parsing the token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
this(tokenId, context,
|
||||
new ByteArrayInputStream(tokenBytes, tokenOffset, tokenLen),
|
||||
prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
||||
* demand and the thread might block if there are not enough bytes to
|
||||
* complete the token. Please note there is no accurate way to find out
|
||||
* the size of a token, but we try our best to make sure there is
|
||||
* enough bytes to construct one.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param is the InputStream from which to read
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem reading from the
|
||||
* InputStream or parsing the token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context, InputStream is,
|
||||
MessageProp prop) throws GSSException {
|
||||
init(tokenId, context);
|
||||
|
||||
try {
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
tokenHeader = new MessageTokenHeader(is, prop, tokenId);
|
||||
|
||||
// set key_usage
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
key_usage = (!initiator ? KG_USAGE_INITIATOR_SEAL
|
||||
: KG_USAGE_ACCEPTOR_SEAL);
|
||||
} else if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
key_usage = (!initiator ? KG_USAGE_INITIATOR_SIGN
|
||||
: KG_USAGE_ACCEPTOR_SIGN);
|
||||
}
|
||||
|
||||
int minSize = 0; // minimal size for token data
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && prop.getPrivacy()) {
|
||||
minSize = CONFOUNDER_SIZE +
|
||||
TOKEN_HEADER_SIZE + cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
minSize = cipherHelper.getChecksumLength();
|
||||
}
|
||||
|
||||
// Read token data
|
||||
if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
// The only case we can precisely predict the token data length
|
||||
tokenDataLen = minSize;
|
||||
tokenData = new byte[minSize];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
tokenDataLen = is.available();
|
||||
if (tokenDataLen >= minSize) { // read in one shot
|
||||
tokenData = new byte[tokenDataLen];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
byte[] tmp = new byte[minSize];
|
||||
readFully(is, tmp);
|
||||
// Hope while blocked in the read above, more data would
|
||||
// come and is.available() below contains the whole token.
|
||||
int more = is.available();
|
||||
tokenDataLen = minSize + more;
|
||||
tokenData = Arrays.copyOf(tmp, tokenDataLen);
|
||||
readFully(is, tokenData, minSize, more);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
rotate();
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.MIC_ID_v2 ||
|
||||
(tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy())) {
|
||||
// Read checksum
|
||||
int chkLen = cipherHelper.getChecksumLength();
|
||||
checksum = new byte[chkLen];
|
||||
System.arraycopy(tokenData, tokenDataLen-chkLen,
|
||||
checksum, 0, chkLen);
|
||||
|
||||
// validate EC for Wrap tokens without confidentiality
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy()) {
|
||||
if (chkLen != ec) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "EC incorrect!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the token id that was contained in this token.
|
||||
* @return the token id in the token
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the key_usage type for this token.
|
||||
* @return the key_usage for the token
|
||||
*/
|
||||
public final int getKeyUsage() {
|
||||
return key_usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if this token contains any encrypted data.
|
||||
* @return true if it contains any encrypted data, false if there is only
|
||||
* plaintext data or if there is no data.
|
||||
*/
|
||||
public final boolean getConfState() {
|
||||
return confState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the checksum field and the sequence number field.
|
||||
*
|
||||
* @param prop the MessageProp structure
|
||||
* @param data the application data to checksum
|
||||
* @param offset the offset where the data starts
|
||||
* @param len the length of the data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* sequence number calculation.
|
||||
*/
|
||||
public void genSignAndSeqNumber(MessageProp prop,
|
||||
byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
|
||||
|
||||
int qop = prop.getQOP();
|
||||
if (qop != 0) {
|
||||
qop = 0;
|
||||
prop.setQOP(qop);
|
||||
}
|
||||
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// Create a new gss token header as defined in RFC 4121
|
||||
tokenHeader = new MessageTokenHeader(tokenId, prop.getPrivacy());
|
||||
// debug("\n\t Message Header = " +
|
||||
// getHexBytes(tokenHeader.getBytes(), tokenHeader.getBytes().length));
|
||||
|
||||
// set key_usage
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
key_usage = (initiator ? KG_USAGE_INITIATOR_SEAL
|
||||
: KG_USAGE_ACCEPTOR_SEAL);
|
||||
} else if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
key_usage = (initiator ? KG_USAGE_INITIATOR_SIGN
|
||||
: KG_USAGE_ACCEPTOR_SIGN);
|
||||
}
|
||||
|
||||
// Calculate SGN_CKSUM
|
||||
if ((tokenId == MIC_ID_v2) ||
|
||||
(!prop.getPrivacy() && (tokenId == WRAP_ID_v2))) {
|
||||
checksum = getChecksum(data, offset, len);
|
||||
// debug("\n\tCalc checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
}
|
||||
|
||||
// In Wrap tokens without confidentiality, the EC field SHALL be used
|
||||
// to encode the number of octets in the trailing checksum
|
||||
if (!prop.getPrivacy() && (tokenId == WRAP_ID_v2)) {
|
||||
byte[] tok_header = tokenHeader.getBytes();
|
||||
tok_header[4] = (byte) (checksum.length >>> 8);
|
||||
tok_header[5] = (byte) (checksum.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the validity of checksum field
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation
|
||||
*/
|
||||
public final boolean verifySign(byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("\t====In verifySign:====\n");
|
||||
// debug("\t\t checksum: [" + getHexBytes(checksum) + "]\n");
|
||||
// debug("\t\t data = [" + getHexBytes(data) + "]\n");
|
||||
|
||||
byte[] myChecksum = getChecksum(data, offset, len);
|
||||
// debug("\t\t mychecksum: [" + getHexBytes(myChecksum) +"]\n");
|
||||
|
||||
if (MessageDigest.isEqual(checksum, myChecksum)) {
|
||||
// debug("\t\t====Checksum PASS:====\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate bytes as per the "RRC" (Right Rotation Count) received.
|
||||
* Our implementation does not do any rotates when sending, only
|
||||
* when receiving, we rotate left as per the RRC count, to revert it.
|
||||
*/
|
||||
private void rotate() {
|
||||
if (rrc % tokenDataLen != 0) {
|
||||
rrc = rrc % tokenDataLen;
|
||||
byte[] newBytes = new byte[tokenDataLen];
|
||||
|
||||
System.arraycopy(tokenData, rrc, newBytes, 0, tokenDataLen-rrc);
|
||||
System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rrc, rrc);
|
||||
|
||||
tokenData = newBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public final int getSequenceNumber() {
|
||||
return seqNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the checksum based on the algorithm stored in the
|
||||
* tokenHeader.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation.
|
||||
*/
|
||||
byte[] getChecksum(byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Will do getChecksum:\n");
|
||||
|
||||
/*
|
||||
* For checksum calculation the token header bytes i.e., the first 16
|
||||
* bytes following the GSSHeader, are logically prepended to the
|
||||
* application data to bind the data to this particular token.
|
||||
*
|
||||
* Note: There is no such requirement wrt adding padding to the
|
||||
* application data for checksumming, although the cryptographic
|
||||
* algorithm used might itself apply some padding.
|
||||
*/
|
||||
|
||||
byte[] tokenHeaderBytes = tokenHeader.getBytes();
|
||||
|
||||
// check confidentiality
|
||||
int conf_flag = tokenHeaderBytes[TOKEN_FLAG_POS] &
|
||||
FLAG_WRAP_CONFIDENTIAL;
|
||||
|
||||
// clear EC and RRC in token header for checksum calculation
|
||||
if ((conf_flag == 0) && (tokenId == WRAP_ID_v2)) {
|
||||
tokenHeaderBytes[4] = 0;
|
||||
tokenHeaderBytes[5] = 0;
|
||||
tokenHeaderBytes[6] = 0;
|
||||
tokenHeaderBytes[7] = 0;
|
||||
}
|
||||
return cipherHelper.calculateChecksum(tokenHeaderBytes, data,
|
||||
offset, len, key_usage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an empty MessageToken for the local context to send to
|
||||
* the peer. It also increments the local sequence number in the
|
||||
* Krb5Context instance it uses after obtaining the object lock for
|
||||
* it.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token
|
||||
* @param context the Kerberos context associated with this token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context) throws GSSException {
|
||||
/*
|
||||
debug("\n============================");
|
||||
debug("\nMySessionKey=" +
|
||||
getHexBytes(context.getMySessionKey().getBytes()));
|
||||
debug("\nPeerSessionKey=" +
|
||||
getHexBytes(context.getPeerSessionKey().getBytes()));
|
||||
debug("\n============================\n");
|
||||
*/
|
||||
init(tokenId, context);
|
||||
this.seqNumber = context.incrementMySequenceNumber();
|
||||
}
|
||||
|
||||
private void init(int tokenId, Krb5Context context) throws GSSException {
|
||||
this.tokenId = tokenId;
|
||||
// Just for consistency check in Wrap
|
||||
this.confState = context.getConfState();
|
||||
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
this.have_acceptor_subkey = context.getKeySrc() == Krb5Context.ACCEPTOR_SUBKEY;
|
||||
|
||||
this.cipherHelper = context.getCipherHelper(null);
|
||||
// debug("In MessageToken.Cons");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a MessageTokenHeader onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws IOException is an error occurs while writing to the OutputStream
|
||||
*/
|
||||
protected void encodeHeader(OutputStream os) throws IOException {
|
||||
tokenHeader.encode(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a MessageToken_v2 onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws IOException is an error occurs while encoding the token
|
||||
*/
|
||||
public abstract void encode(OutputStream os) throws IOException;
|
||||
|
||||
protected final byte[] getTokenHeader() {
|
||||
return (tokenHeader.getBytes());
|
||||
}
|
||||
|
||||
// ******************************************* //
|
||||
// I N N E R C L A S S E S F O L L O W
|
||||
// ******************************************* //
|
||||
|
||||
/**
|
||||
* This inner class represents the initial portion of the message token.
|
||||
* It constitutes the first 16 bytes of the message token.
|
||||
*/
|
||||
class MessageTokenHeader {
|
||||
|
||||
private int tokenId;
|
||||
private byte[] bytes = new byte[TOKEN_HEADER_SIZE];
|
||||
|
||||
// Writes a new token header
|
||||
public MessageTokenHeader(int tokenId, boolean conf) throws GSSException {
|
||||
|
||||
this.tokenId = tokenId;
|
||||
|
||||
bytes[0] = (byte) (tokenId >>> 8);
|
||||
bytes[1] = (byte) (tokenId);
|
||||
|
||||
// Flags (Note: MIT impl requires subkey)
|
||||
int flags = 0;
|
||||
flags = (initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) |
|
||||
((conf && tokenId != MIC_ID_v2) ?
|
||||
FLAG_WRAP_CONFIDENTIAL : 0) |
|
||||
(have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0);
|
||||
bytes[2] = (byte) flags;
|
||||
|
||||
// filler
|
||||
bytes[3] = (byte) FILLER;
|
||||
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// EC field
|
||||
bytes[4] = (byte) 0;
|
||||
bytes[5] = (byte) 0;
|
||||
// RRC field
|
||||
bytes[6] = (byte) 0;
|
||||
bytes[7] = (byte) 0;
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
// more filler for MicToken
|
||||
for (int i = 4; i < 8; i++) {
|
||||
bytes[i] = (byte) FILLER;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate SND_SEQ, only write 4 bytes from the 12th position
|
||||
writeBigEndian(seqNumber, bytes, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a MessageTokenHeader from an InputStream and sets the
|
||||
* appropriate confidentiality and quality of protection
|
||||
* values in a MessageProp structure.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param prop the MessageProp to populate
|
||||
* @throws IOException is an error occurs while reading from the
|
||||
* InputStream
|
||||
*/
|
||||
public MessageTokenHeader(InputStream is, MessageProp prop, int tokId)
|
||||
throws IOException, GSSException {
|
||||
|
||||
readFully(is, bytes, 0, TOKEN_HEADER_SIZE);
|
||||
tokenId = readInt(bytes, TOKEN_ID_POS);
|
||||
|
||||
// validate Token ID
|
||||
if (tokenId != tokId) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token ID!");
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate new GSS TokenHeader
|
||||
*/
|
||||
|
||||
// valid acceptor_flag
|
||||
// If I am initiator, the received token should have ACCEPTOR on
|
||||
int acceptor_flag = (initiator ? FLAG_SENDER_IS_ACCEPTOR : 0);
|
||||
int flag = bytes[TOKEN_FLAG_POS] & FLAG_SENDER_IS_ACCEPTOR;
|
||||
if (flag != acceptor_flag) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Acceptor Flag Error!");
|
||||
}
|
||||
|
||||
// check for confidentiality
|
||||
int conf_flag = bytes[TOKEN_FLAG_POS] & FLAG_WRAP_CONFIDENTIAL;
|
||||
if ((conf_flag == FLAG_WRAP_CONFIDENTIAL) &&
|
||||
(tokenId == WRAP_ID_v2)) {
|
||||
prop.setPrivacy(true);
|
||||
} else {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// validate filler
|
||||
if ((bytes[3] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token Filler!");
|
||||
}
|
||||
|
||||
// read EC field
|
||||
ec = readBigEndian(bytes, TOKEN_EC_POS, 2);
|
||||
|
||||
// read RRC field
|
||||
rrc = readBigEndian(bytes, TOKEN_RRC_POS, 2);
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
for (int i = 3; i < 8; i++) {
|
||||
if ((bytes[i] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN,
|
||||
-1, getTokenName(tokenId) + ":" +
|
||||
"Defective Token Filler!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set default QOP
|
||||
prop.setQOP(0);
|
||||
|
||||
// sequence number
|
||||
seqNumber = readBigEndian(bytes, 12, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this MessageTokenHeader onto an OutputStream
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException is an error occurs while writing
|
||||
*/
|
||||
public final void encode(OutputStream os) throws IOException {
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the token id for the message token.
|
||||
* @return the token id
|
||||
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID_v2
|
||||
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID_v2
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes of this header.
|
||||
* @return 8 bytes that form this header
|
||||
*/
|
||||
public final byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
} // end of class MessageTokenHeader
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken.java
Normal file
114
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
class MicToken extends MessageToken {
|
||||
|
||||
public MicToken(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context, is, prop);
|
||||
}
|
||||
|
||||
public void verify(byte[] data, int offset, int len) throws GSSException {
|
||||
if (!verifySignAndSeqNumber(null, data, offset, len, null))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
|
||||
public void verify(InputStream data) throws GSSException {
|
||||
byte[] dataBytes = null;
|
||||
try {
|
||||
dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
} catch (IOException e) {
|
||||
// Error reading application data
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
verify(dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context, MessageProp prop,
|
||||
byte[] data, int pos, int len)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context);
|
||||
|
||||
// debug("Application data to MicToken verify is [" +
|
||||
// getHexBytes(data, pos, len) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, null, data, pos, len, null);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context, MessageProp prop,
|
||||
InputStream data)
|
||||
throws GSSException, IOException {
|
||||
super(Krb5Token.MIC_ID, context);
|
||||
byte[] dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
|
||||
//debug("Application data to MicToken cons is [" +
|
||||
// getHexBytes(dataBytes) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, null, dataBytes, 0, dataBytes.length, null);
|
||||
}
|
||||
|
||||
protected int getSealAlg(boolean confRequested, int qop) {
|
||||
return (SEAL_ALG_NONE);
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
// Token is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] token = bos.toByteArray();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException{
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
118
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken_v2.java
Normal file
118
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken_v2.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS MIC tokens, as specified
|
||||
* in RFC 4121
|
||||
*
|
||||
* MIC tokens = { 16-byte token-header | HMAC }
|
||||
* where HMAC is on { plaintext | 16-byte token-header }
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
|
||||
class MicToken_v2 extends MessageToken_v2 {
|
||||
|
||||
public MicToken_v2(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context, is, prop);
|
||||
}
|
||||
|
||||
public void verify(byte[] data, int offset, int len) throws GSSException {
|
||||
if (!verifySign(data, offset, len))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
|
||||
public void verify(InputStream data) throws GSSException {
|
||||
byte[] dataBytes = null;
|
||||
try {
|
||||
dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
} catch (IOException e) {
|
||||
// Error reading application data
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
verify(dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] data, int pos, int len)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
|
||||
// debug("Application data to MicToken verify is [" +
|
||||
// getHexBytes(data, pos, len) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, data, pos, len);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop, InputStream data)
|
||||
throws GSSException, IOException {
|
||||
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
byte[] dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
|
||||
// debug("Application data to MicToken cons is [" +
|
||||
// getHexBytes(dataBytes) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(checksum);
|
||||
}
|
||||
}
|
||||
262
jdkSrc/jdk8/sun/security/jgss/krb5/ServiceCreds.java
Normal file
262
jdkSrc/jdk8/sun/security/jgss/krb5/ServiceCreds.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.KrbException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.Krb5;
|
||||
|
||||
/**
|
||||
* Credentials of a kerberos acceptor. A KerberosPrincipal object (kp) is
|
||||
* the principal. It can be specified as the serverPrincipal argument
|
||||
* in the getInstance() method, or uses only KerberosPrincipal in the subject.
|
||||
* Otherwise, the creds object is unbound and kp is null.
|
||||
*
|
||||
* The class also encapsulates various secrets, which can be:
|
||||
*
|
||||
* 1. Some KerberosKeys (generated from password)
|
||||
* 2. Some KeyTabs (for a typical service based on keytabs)
|
||||
* 3. A TGT (for S4U2proxy extension or user2user)
|
||||
*
|
||||
* Note that some secrets can coexist. For example, a user2user service
|
||||
* can use its keytab (or keys) if the client can successfully obtain a
|
||||
* normal service ticket, or it can use the TGT (actually, the session key
|
||||
* of the TGT) if the client can only acquire a service ticket
|
||||
* of ENC-TKT-IN-SKEY style.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class ServiceCreds {
|
||||
// The principal, or null if unbound
|
||||
private KerberosPrincipal kp;
|
||||
|
||||
// All principals in the subject's princ set
|
||||
private Set<KerberosPrincipal> allPrincs;
|
||||
|
||||
// All private credentials that can be used
|
||||
private List<KeyTab> ktabs;
|
||||
private List<KerberosKey> kk;
|
||||
private KerberosTicket tgt;
|
||||
|
||||
private boolean destroyed;
|
||||
|
||||
private ServiceCreds() {
|
||||
// Make sure this class cannot be instantiated externally.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ServiceCreds object based on info in a Subject for
|
||||
* a given principal name (if specified).
|
||||
* @return the object, or null if there is no private creds for it
|
||||
*/
|
||||
public static ServiceCreds getInstance(
|
||||
Subject subj, String serverPrincipal) {
|
||||
|
||||
ServiceCreds sc = new ServiceCreds();
|
||||
|
||||
sc.allPrincs =
|
||||
subj.getPrincipals(KerberosPrincipal.class);
|
||||
|
||||
// Compatibility. A key implies its own principal
|
||||
for (KerberosKey key: SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KerberosKey.class)) {
|
||||
sc.allPrincs.add(key.getPrincipal());
|
||||
}
|
||||
|
||||
if (serverPrincipal != null) { // A named principal
|
||||
sc.kp = new KerberosPrincipal(serverPrincipal);
|
||||
} else {
|
||||
// For compatibility reason, we set the name of default principal
|
||||
// to the "only possible" name it can take, which means there is
|
||||
// only one KerberosPrincipal and there is no unbound keytabs
|
||||
if (sc.allPrincs.size() == 1) {
|
||||
boolean hasUnbound = false;
|
||||
for (KeyTab ktab: SubjectComber.findMany(
|
||||
subj, null, null, KeyTab.class)) {
|
||||
if (!ktab.isBound()) {
|
||||
hasUnbound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasUnbound) {
|
||||
sc.kp = sc.allPrincs.iterator().next();
|
||||
serverPrincipal = sc.kp.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc.ktabs = SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KeyTab.class);
|
||||
sc.kk = SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KerberosKey.class);
|
||||
sc.tgt = SubjectComber.find(
|
||||
subj, null, serverPrincipal, KerberosTicket.class);
|
||||
if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
sc.destroyed = false;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
// can be null
|
||||
public String getName() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
return kp == null ? null : kp.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets keys for "someone". Used in 2 cases:
|
||||
* 1. By TLS because it needs to get keys before client comes in.
|
||||
* 2. As a fallback in getEKeys() below.
|
||||
* This method can still return an empty array.
|
||||
*/
|
||||
public KerberosKey[] getKKeys() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
KerberosPrincipal one = kp; // named principal
|
||||
if (one == null && !allPrincs.isEmpty()) { // or, a known principal
|
||||
one = allPrincs.iterator().next();
|
||||
}
|
||||
if (one == null) { // Or, some random one
|
||||
for (KeyTab ktab: ktabs) {
|
||||
// Must be unbound keytab, otherwise, allPrincs is not empty
|
||||
PrincipalName pn =
|
||||
Krb5Util.snapshotFromJavaxKeyTab(ktab).getOneName();
|
||||
if (pn != null) {
|
||||
one = new KerberosPrincipal(pn.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (one != null) {
|
||||
return getKKeys(one);
|
||||
} else {
|
||||
return new KerberosKey[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kkeys for a principal,
|
||||
* @param princ the target name initiator requests. Not null.
|
||||
* @return keys for the princ, never null, might be empty
|
||||
*/
|
||||
public KerberosKey[] getKKeys(KerberosPrincipal princ) {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
ArrayList<KerberosKey> keys = new ArrayList<>();
|
||||
if (kp != null && !princ.equals(kp)) { // named principal
|
||||
return new KerberosKey[0];
|
||||
}
|
||||
for (KerberosKey k: kk) {
|
||||
if (k.getPrincipal().equals(princ)) {
|
||||
keys.add(k);
|
||||
}
|
||||
}
|
||||
for (KeyTab ktab: ktabs) {
|
||||
if (ktab.getPrincipal() == null && ktab.isBound()) {
|
||||
// legacy bound keytab. although we don't know who
|
||||
// the bound principal is, it must be in allPrincs
|
||||
if (!allPrincs.contains(princ)) {
|
||||
continue; // skip this legacy bound keytab
|
||||
}
|
||||
}
|
||||
for (KerberosKey k: ktab.getKeys(princ)) {
|
||||
keys.add(k);
|
||||
}
|
||||
}
|
||||
return keys.toArray(new KerberosKey[keys.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets EKeys for a principal.
|
||||
* @param princ the target name initiator requests. Not null.
|
||||
* @return keys for the princ, never null, might be empty
|
||||
*/
|
||||
public EncryptionKey[] getEKeys(PrincipalName princ) {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName()));
|
||||
if (kkeys.length == 0) {
|
||||
// Fallback: old JDK does not perform real name checking. If the
|
||||
// acceptor has host.sun.com but initiator requests for host,
|
||||
// as long as their keys match (i.e. keys for one can decrypt
|
||||
// the other's service ticket), the authentication is OK.
|
||||
// There are real customers depending on this to use different
|
||||
// names for a single service.
|
||||
kkeys = getKKeys();
|
||||
}
|
||||
EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
|
||||
for (int i=0; i<ekeys.length; i++) {
|
||||
ekeys[i] = new EncryptionKey(
|
||||
kkeys[i].getEncoded(), kkeys[i].getKeyType(),
|
||||
new Integer(kkeys[i].getVersionNumber()));
|
||||
}
|
||||
return ekeys;
|
||||
}
|
||||
|
||||
public Credentials getInitCred() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
if (tgt == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Krb5Util.ticketToCreds(tgt);
|
||||
} catch (KrbException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// Do not wipe out real keys because they are references to the
|
||||
// priv creds in subject. Just make it useless.
|
||||
destroyed = true;
|
||||
kp = null;
|
||||
ktabs.clear();
|
||||
kk.clear();
|
||||
tgt = null;
|
||||
}
|
||||
}
|
||||
251
jdkSrc/jdk8/sun/security/jgss/krb5/SubjectComber.java
Normal file
251
jdkSrc/jdk8/sun/security/jgss/krb5/SubjectComber.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import sun.security.krb5.JavaxSecurityAuthKerberosAccess;
|
||||
import sun.security.krb5.KerberosSecrets;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
|
||||
/**
|
||||
* This utility looks through the current Subject and retrieves private
|
||||
* credentials for the desired client/server principals.
|
||||
*
|
||||
* @author Ram Marti
|
||||
* @since 1.4.2
|
||||
*/
|
||||
|
||||
class SubjectComber {
|
||||
|
||||
private static final boolean DEBUG = Krb5Util.DEBUG;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private SubjectComber() { // Cannot create one of these
|
||||
}
|
||||
|
||||
static <T> T find(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass) {
|
||||
|
||||
// findAux returns T if oneOnly.
|
||||
return credClass.cast(findAux(subject, serverPrincipal,
|
||||
clientPrincipal, credClass, true));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // findAux returns List<T> if !oneOnly.
|
||||
static <T> List<T> findMany(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass) {
|
||||
|
||||
return (List<T>)findAux(subject, serverPrincipal, clientPrincipal,
|
||||
credClass, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find private credentials for the specified client/server principals
|
||||
* in the subject. Returns null if the subject is null.
|
||||
*
|
||||
* @return the private credentials
|
||||
*/
|
||||
// Returns T if oneOnly and List<T> if !oneOnly.
|
||||
private static <T> Object findAux(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass, boolean oneOnly) {
|
||||
|
||||
if (subject == null) {
|
||||
return null;
|
||||
} else {
|
||||
List<T> answer = (oneOnly ? null : new ArrayList<T>());
|
||||
|
||||
if (credClass == KeyTab.class) {
|
||||
Iterator<KeyTab> iterator =
|
||||
subject.getPrivateCredentials(KeyTab.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
KeyTab t = iterator.next();
|
||||
if (serverPrincipal != null && t.isBound()) {
|
||||
KerberosPrincipal name = t.getPrincipal();
|
||||
if (name != null) {
|
||||
if (!serverPrincipal.equals(name.getName())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// legacy bound keytab. although we don't know who
|
||||
// the bound principal is, it must be in allPrincs
|
||||
boolean found = false;
|
||||
for (KerberosPrincipal princ:
|
||||
subject.getPrincipals(KerberosPrincipal.class)) {
|
||||
if (princ.getName().equals(serverPrincipal)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) continue;
|
||||
}
|
||||
}
|
||||
// Check passed, we can add now
|
||||
if (DEBUG) {
|
||||
System.out.println("Found " + credClass.getSimpleName()
|
||||
+ " " + t);
|
||||
}
|
||||
if (oneOnly) {
|
||||
return t;
|
||||
} else {
|
||||
answer.add(credClass.cast(t));
|
||||
}
|
||||
}
|
||||
} else if (credClass == KerberosKey.class) {
|
||||
// We are looking for credentials for the serverPrincipal
|
||||
Iterator<KerberosKey> iterator =
|
||||
subject.getPrivateCredentials(KerberosKey.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
KerberosKey t = iterator.next();
|
||||
String name = t.getPrincipal().getName();
|
||||
if (serverPrincipal == null || serverPrincipal.equals(name)) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Found " +
|
||||
credClass.getSimpleName() + " for " + name);
|
||||
}
|
||||
if (oneOnly) {
|
||||
return t;
|
||||
} else {
|
||||
answer.add(credClass.cast(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (credClass == KerberosTicket.class) {
|
||||
// we are looking for a KerberosTicket credentials
|
||||
// for client-service principal pair
|
||||
Set<Object> pcs = subject.getPrivateCredentials();
|
||||
synchronized (pcs) {
|
||||
Iterator<Object> iterator = pcs.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object obj = iterator.next();
|
||||
if (!(obj instanceof KerberosTicket)) {
|
||||
continue;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
KerberosTicket ticket = (KerberosTicket)obj;
|
||||
if (DEBUG) {
|
||||
System.out.println("Found ticket for "
|
||||
+ ticket.getClient()
|
||||
+ " to go to "
|
||||
+ ticket.getServer()
|
||||
+ " expiring on "
|
||||
+ ticket.getEndTime());
|
||||
}
|
||||
if (!ticket.isCurrent()) {
|
||||
// let us remove the ticket from the Subject
|
||||
// Note that both TGT and service ticket will be
|
||||
// removed upon expiration
|
||||
if (!subject.isReadOnly()) {
|
||||
iterator.remove();
|
||||
try {
|
||||
ticket.destroy();
|
||||
if (DEBUG) {
|
||||
System.out.println("Removed and destroyed "
|
||||
+ "the expired Ticket \n"
|
||||
+ ticket);
|
||||
|
||||
}
|
||||
} catch (DestroyFailedException dfe) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Expired ticket not" +
|
||||
" detroyed successfully. " + dfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String serverMatch = findServerMatch(serverPrincipal, ticket);
|
||||
if (serverMatch != null) {
|
||||
String clientMatch = findClientMatch(clientPrincipal, ticket);
|
||||
if (clientMatch != null) {
|
||||
if (oneOnly) {
|
||||
return ticket;
|
||||
} else {
|
||||
// Record names so that tickets will
|
||||
// all belong to same principals
|
||||
if (clientPrincipal == null) {
|
||||
clientPrincipal = clientMatch;
|
||||
}
|
||||
if (serverPrincipal == null) {
|
||||
serverPrincipal = serverMatch;
|
||||
}
|
||||
answer.add(credClass.cast(ticket));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
private static String findServerMatch(String input, KerberosTicket ticket) {
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(ticket);
|
||||
if (input != null) {
|
||||
return ((serverAlias != null && input.equals(serverAlias.getName())) ||
|
||||
input.equals(ticket.getServer().getName()))
|
||||
? input : null;
|
||||
} else {
|
||||
return serverAlias != null
|
||||
? serverAlias.getName()
|
||||
: ticket.getServer().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private static String findClientMatch(String input, KerberosTicket ticket) {
|
||||
JavaxSecurityAuthKerberosAccess access = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess();
|
||||
KerberosPrincipal clientAlias = access.kerberosTicketGetClientAlias(ticket);
|
||||
KerberosTicket proxy = access.kerberosTicketGetProxy(ticket);
|
||||
if (input != null) {
|
||||
return ((clientAlias != null && input.equals(clientAlias.getName())) ||
|
||||
(proxy != null && input.equals(proxy.getClient().getName())) ||
|
||||
(proxy == null && input.equals(ticket.getClient().getName())))
|
||||
? input : null;
|
||||
} else {
|
||||
if (clientAlias != null) {
|
||||
return clientAlias.getName();
|
||||
} else if (proxy != null) {
|
||||
return proxy.getClient().getName();
|
||||
} else {
|
||||
return ticket.getClient().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import sun.security.krb5.Confounder;
|
||||
|
||||
/**
|
||||
* This class represents a token emitted by the GSSContext.wrap()
|
||||
* call. It is a MessageToken except that it also contains plaintext
|
||||
* or encrypted data at the end. A wrapToken has certain other rules
|
||||
* that are peculiar to it and different from a MICToken, which is
|
||||
* another type of MessageToken. All data in a WrapToken is prepended
|
||||
* by a random counfounder of 8 bytes. All data in a WrapToken is
|
||||
* also padded with one to eight bytes where all bytes are equal in
|
||||
* value to the number of bytes being padded. Thus, all application
|
||||
* data is replaced by (confounder || data || padding).
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
class WrapToken extends MessageToken {
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
static final int CONFOUNDER_SIZE = 8;
|
||||
|
||||
/*
|
||||
* The padding used with a WrapToken. All data is padded to the
|
||||
* next multiple of 8 bytes, even if its length is already
|
||||
* multiple of 8.
|
||||
* Use this table as a quick way to obtain padding bytes by
|
||||
* indexing it with the number of padding bytes required.
|
||||
*/
|
||||
static final byte[][] pads = {
|
||||
null, // No, no one escapes padding
|
||||
{0x01},
|
||||
{0x02, 0x02},
|
||||
{0x03, 0x03, 0x03},
|
||||
{0x04, 0x04, 0x04, 0x04},
|
||||
{0x05, 0x05, 0x05, 0x05, 0x05},
|
||||
{0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
|
||||
{0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07},
|
||||
{0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}
|
||||
};
|
||||
|
||||
/*
|
||||
* A token may come in either in an InputStream or as a
|
||||
* byte[]. Store a reference to it in either case and process
|
||||
* it's data only later when getData() is called and
|
||||
* decryption/copying is needed to be done. Note that JCE can
|
||||
* decrypt both from a byte[] and from an InputStream.
|
||||
*/
|
||||
private boolean readTokenFromInputStream = true;
|
||||
private InputStream is = null;
|
||||
private byte[] tokenBytes = null;
|
||||
private int tokenOffset = 0;
|
||||
private int tokenLen = 0;
|
||||
|
||||
/*
|
||||
* Application data may come from an InputStream or from a
|
||||
* byte[]. However, it will always be stored and processed as a
|
||||
* byte[] since
|
||||
* (a) the MessageDigest class only accepts a byte[] as input and
|
||||
* (b) It allows writing to an OuputStream via a CipherOutputStream.
|
||||
*/
|
||||
private byte[] dataBytes = null;
|
||||
private int dataOffset = 0;
|
||||
private int dataLen = 0;
|
||||
|
||||
// the len of the token data: (confounder || data || padding)
|
||||
private int dataSize = 0;
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
byte[] padding = null;
|
||||
|
||||
private boolean privacy = false;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
* peer.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param tokenBytes the bytes of the token
|
||||
* @param tokenOffset the offset of the token
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
|
||||
this.readTokenFromInputStream = false;
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.tokenBytes = tokenBytes;
|
||||
this.tokenOffset = tokenOffset;
|
||||
this.tokenLen = tokenLen;
|
||||
this.privacy = prop.getPrivacy();
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getKrb5TokenSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes read on the fly from
|
||||
* an InputStream.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param is the InputStream containing the token bytes
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective or if there is
|
||||
* a problem reading from the InputStream
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context, is, prop);
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.is = is;
|
||||
this.privacy = prop.getPrivacy();
|
||||
/*
|
||||
debug("WrapToken Cons: gssHeader.getMechTokenLength=" +
|
||||
getGSSHeader().getMechTokenLength());
|
||||
debug("\n token size="
|
||||
+ getTokenSize());
|
||||
*/
|
||||
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getTokenSize();
|
||||
// debug("\n dataSize=" + dataSize);
|
||||
// debug("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken.
|
||||
* @return a byte array containing the application data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[dataSize];
|
||||
getData(temp, 0);
|
||||
|
||||
// Remove the confounder and the padding
|
||||
byte[] retVal = new byte[dataSize - confounder.length -
|
||||
padding.length];
|
||||
System.arraycopy(temp, 0, retVal, 0, retVal.length);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken, writing it into an application provided output
|
||||
* array.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @return the size of the data written
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
if (readTokenFromInputStream)
|
||||
getDataFromStream(dataBuf, dataBufOffset);
|
||||
else
|
||||
getDataFromBuffer(dataBuf, dataBufOffset);
|
||||
|
||||
return (dataSize - confounder.length - padding.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with a byte array as input.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromBuffer(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
int dataPos = tokenOffset +
|
||||
gssHeader.getLength() + getTokenSize();
|
||||
|
||||
if (dataPos + dataSize > tokenOffset + tokenLen)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Insufficient data in "
|
||||
+ getTokenName(getTokenId()));
|
||||
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this,
|
||||
tokenBytes, dataPos, dataSize, dataBuf, dataBufOffset);
|
||||
/*
|
||||
debug("\t\tDecrypted data is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
getHexBytes(padding) +
|
||||
"]\n");
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
System.arraycopy(tokenBytes, dataPos,
|
||||
confounder, 0, CONFOUNDER_SIZE);
|
||||
int padSize = tokenBytes[dataPos + dataSize - 1];
|
||||
if (padSize < 0)
|
||||
padSize = 0;
|
||||
if (padSize > 8)
|
||||
padSize %= 8;
|
||||
|
||||
padding = pads[padSize];
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
|
||||
System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
dataBuf, dataBufOffset, dataSize -
|
||||
CONFOUNDER_SIZE - padSize);
|
||||
|
||||
// byte[] debugbuf = new byte[dataSize - CONFOUNDER_SIZE - padSize];
|
||||
// System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
// debugbuf, 0, debugbuf.length);
|
||||
// debug("\t\tData is: " + getHexBytes(debugbuf, debugbuf.length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with an Inputstream.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromStream(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
|
||||
// Don't check the token length. Data will be read on demand from
|
||||
// the InputStream.
|
||||
|
||||
// debug("WrapToken cons: data will be read from InputStream.\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
try {
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this, is, dataSize,
|
||||
dataBuf, dataBufOffset);
|
||||
|
||||
// debug("\t\tDecrypted data is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBuf, dataBufOffset,
|
||||
// dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
// getHexBytes(padding) +
|
||||
// "]\n");
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
readFully(is, confounder);
|
||||
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padding = pads[1];
|
||||
readFully(is, dataBuf, dataBufOffset, dataSize-CONFOUNDER_SIZE-1);
|
||||
} else {
|
||||
// Data is always a multiple of 8 with this GSS Mech
|
||||
// Copy all but last block as they are
|
||||
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
|
||||
int offset = dataBufOffset;
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
readFully(is, dataBuf, offset, 8);
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
byte[] finalBlock = new byte[8];
|
||||
readFully(is, finalBlock);
|
||||
|
||||
int padSize = finalBlock[7];
|
||||
padding = pads[padSize];
|
||||
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
System.arraycopy(finalBlock, 0, dataBuf, offset,
|
||||
finalBlock.length - padSize);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(getTokenId())
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper routine to pick the right padding for a certain length
|
||||
* of application data. Every application message has some
|
||||
* padding between 1 and 8 bytes.
|
||||
* @param len the length of the application data
|
||||
* @return the padding to be applied
|
||||
*/
|
||||
private byte[] getPadding(int len) {
|
||||
int padSize = 0;
|
||||
// For RC4-HMAC, all padding is rounded up to 1 byte.
|
||||
// One byte is needed to say that there is 1 byte of padding.
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padSize = 1;
|
||||
} else {
|
||||
padSize = len % 8;
|
||||
padSize = 8 - padSize;
|
||||
}
|
||||
return pads[padSize];
|
||||
}
|
||||
|
||||
public WrapToken(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
padding = getPadding(dataLen);
|
||||
dataSize = confounder.length + dataLen + padding.length;
|
||||
this.dataBytes = dataBytes;
|
||||
this.dataOffset = dataOffset;
|
||||
this.dataLen = dataLen;
|
||||
|
||||
/*
|
||||
debug("\nWrapToken cons: data to wrap is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBytes, dataOffset, dataLen) + " " +
|
||||
// padding is never null for Wrap
|
||||
getHexBytes(padding) + "]\n");
|
||||
*/
|
||||
|
||||
genSignAndSeqNumber(prop,
|
||||
confounder,
|
||||
dataBytes, dataOffset, dataLen,
|
||||
padding);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
* did not negotiate for it, do not provide it. The peer might not
|
||||
* have support for it. The app will realize this with a call to
|
||||
* pop.getPrivacy() after wrap().
|
||||
*/
|
||||
if (!context.getConfState())
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
|
||||
super.encode(os);
|
||||
|
||||
// debug("Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
os.write(confounder);
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
os.write(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
os.write(padding);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder,
|
||||
dataBytes, dataOffset, dataLen, padding, os);
|
||||
}
|
||||
// debug("]\n");
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(dataSize + 50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// Token header is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] header = bos.toByteArray();
|
||||
System.arraycopy(header, 0, outToken, offset, header.length);
|
||||
offset += header.length;
|
||||
|
||||
// debug("WrapToken.encode: Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
System.arraycopy(confounder, 0, outToken, offset,
|
||||
confounder.length);
|
||||
offset += confounder.length;
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
System.arraycopy(dataBytes, dataOffset, outToken, offset,
|
||||
dataLen);
|
||||
offset += dataLen;
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
System.arraycopy(padding, 0, outToken, offset, padding.length);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder, dataBytes,
|
||||
dataOffset, dataLen, padding, outToken, offset);
|
||||
|
||||
// debug(getHexBytes(outToken, offset, dataSize));
|
||||
}
|
||||
|
||||
// debug("]\n");
|
||||
|
||||
// %%% assume that plaintext length == ciphertext len
|
||||
return (header.length + confounder.length + dataLen + padding.length);
|
||||
|
||||
}
|
||||
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return (getTokenSize() + dataSize);
|
||||
}
|
||||
|
||||
protected int getSealAlg(boolean conf, int qop) throws GSSException {
|
||||
if (!conf) {
|
||||
return SEAL_ALG_NONE;
|
||||
}
|
||||
|
||||
// ignore QOP
|
||||
return cipherHelper.getSealAlg();
|
||||
}
|
||||
|
||||
// This implementation is way too conservative. And it certainly
|
||||
// doesn't return the maximum limit.
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(getTokenSize(ch) + CONFOUNDER_SIZE) - 8); /* safety */
|
||||
}
|
||||
|
||||
}
|
||||
231
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken_v2.java
Normal file
231
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken_v2.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
import sun.security.krb5.Confounder;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS tokens, as specified in RFC
|
||||
* 4121, emitted by the GSSContext.wrap() call. It is a MessageToken except
|
||||
* that it also contains plaintext or encrypted data at the end. A WrapToken
|
||||
* has certain other rules that are peculiar to it and different from a
|
||||
* MICToken, which is another type of MessageToken. All data in a WrapToken is
|
||||
* prepended by a random confounder of 16 bytes. Thus, all application data
|
||||
* is replaced by (confounder || data || tokenHeader || checksum).
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
class WrapToken_v2 extends MessageToken_v2 {
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
|
||||
private final boolean privacy;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
* peer.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param tokenBytes the bytes of the token
|
||||
* @param tokenOffset the offset of the token
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
this.privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes read on the fly from
|
||||
* an InputStream.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param is the InputStream containing the token bytes
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective or if there is
|
||||
* a problem reading from the InputStream
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context, is, prop);
|
||||
this.privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken.
|
||||
* @return a byte array containing the application data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[tokenDataLen];
|
||||
int len = getData(temp, 0);
|
||||
return Arrays.copyOf(temp, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken, writing it into an application provided output
|
||||
* array.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @return the size of the data written
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
if (privacy) {
|
||||
|
||||
// decrypt data
|
||||
cipherHelper.decryptData(this, tokenData, 0, tokenDataLen,
|
||||
dataBuf, dataBufOffset, getKeyUsage());
|
||||
|
||||
return tokenDataLen - CONFOUNDER_SIZE -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
|
||||
// data
|
||||
int data_length = tokenDataLen - cipherHelper.getChecksumLength();
|
||||
System.arraycopy(tokenData, 0,
|
||||
dataBuf, dataBufOffset,
|
||||
data_length);
|
||||
// debug("\t\tData is: " + getHexBytes(dataBuf, data_length));
|
||||
|
||||
/*
|
||||
* Make sure checksum is not corrupt
|
||||
*/
|
||||
if (!verifySign(dataBuf, dataBufOffset, data_length)) {
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum in Wrap token");
|
||||
}
|
||||
return data_length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a WrapToken_v2 object
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
// debug("\nWrapToken cons: data to wrap is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBytes, dataOffset, dataLen) + "]\n");
|
||||
|
||||
genSignAndSeqNumber(prop, dataBytes, dataOffset, dataLen);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
* did not negotiate for it, do not provide it. The peer might not
|
||||
* have support for it. The app will realize this with a call to
|
||||
* pop.getPrivacy() after wrap().
|
||||
*/
|
||||
if (!context.getConfState())
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
|
||||
if (!privacy) {
|
||||
// Wrap Tokens (without confidentiality) =
|
||||
// { 16 byte token_header | plaintext | 12-byte HMAC }
|
||||
// where HMAC is on { plaintext | token_header }
|
||||
|
||||
tokenData = new byte[dataLen + checksum.length];
|
||||
System.arraycopy(dataBytes, dataOffset, tokenData, 0, dataLen);
|
||||
System.arraycopy(checksum, 0, tokenData, dataLen, checksum.length);
|
||||
} else {
|
||||
// Wrap Tokens (with confidentiality) =
|
||||
// { 16 byte token_header |
|
||||
// Encrypt(16-byte confounder | plaintext | token_header) |
|
||||
// 12-byte HMAC }
|
||||
|
||||
tokenData = cipherHelper.encryptData(this, confounder, getTokenHeader(),
|
||||
dataBytes, dataOffset, dataLen, getKeyUsage());
|
||||
}
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(tokenData);
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(
|
||||
MessageToken_v2.TOKEN_HEADER_SIZE + tokenData.length);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
// This implementation is way to conservative. And it certainly
|
||||
// doesn't return the maximum limit.
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(TOKEN_HEADER_SIZE + ch.getChecksumLength() + CONFOUNDER_SIZE)
|
||||
- 8 /* safety */);
|
||||
}
|
||||
}
|
||||
408
jdkSrc/jdk8/sun/security/jgss/spi/GSSContextSpi.java
Normal file
408
jdkSrc/jdk8/sun/security/jgss/spi/GSSContextSpi.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
package sun.security.jgss.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.Provider;
|
||||
import com.sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific instance of a GSS
|
||||
* security context.
|
||||
* A GSSContextSpi object can be thought of having 3 states:
|
||||
* -before initialization
|
||||
* -during initialization with its peer
|
||||
* -after it is established
|
||||
* <p>
|
||||
* The context options can only be requested in state 1. In state 3,
|
||||
* the per message operations are available to the callers. The get
|
||||
* methods for the context options will return the requested options
|
||||
* while in state 1 and 2, and the established values in state 3.
|
||||
* Some mechanisms may allow the access to the per-message operations
|
||||
* and the context flags before the context is fully established. The
|
||||
* isProtReady method is used to indicate that these services are
|
||||
* available.
|
||||
* <p>
|
||||
* <strong>
|
||||
* Context establishment tokens are defined in a mechanism independent
|
||||
* format in section 3.1 of RFC 2743. The GSS-Framework will add
|
||||
* and remove the mechanism independent header portion of this token format
|
||||
* depending on whether a token is received or is being sent. The mechanism
|
||||
* should only generate or expect to read the inner-context token portion.
|
||||
* <br>
|
||||
* On the other hands, tokens used for per-message calls are generated
|
||||
* entirely by the mechanism. It is possible that the mechanism chooses to
|
||||
* encase inner-level per-message tokens in a header similar to that used
|
||||
* for initial tokens, however, this is upto the mechanism to do. The token
|
||||
* to/from the per-message calls are opaque to the GSS-Framework.
|
||||
* </strong>
|
||||
* <p>
|
||||
* An attempt has been made to allow for reading the peer's tokens from an
|
||||
* InputStream and writing tokens for the peer to an OutputStream. This
|
||||
* allows applications to pass in streams that are obtained from their network
|
||||
* connections and thus minimize the buffer copies that will happen. This
|
||||
* is especially important for tokens generated by wrap() which are
|
||||
* proportional in size to the length of the application data being
|
||||
* wrapped, and are probably also the most frequently used type of tokens.
|
||||
* <p>
|
||||
* It is anticipated that most applications will want to use wrap() in a
|
||||
* fashion where they obtain the application bytes to wrap from a byte[]
|
||||
* but want to output the wrap token straight to an
|
||||
* OutputStream. Similarly, they will want to use unwrap() where they read
|
||||
* the token directly form an InputStream but output it to some byte[] for
|
||||
* the application to process. Unfortunately the high level GSS bindings
|
||||
* do not contain overloaded forms of wrap() and unwrap() that do just
|
||||
* this, however we have accomodated those cases here with the expectation
|
||||
* that this will be rolled into the high level bindings sooner or later.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface GSSContextSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
// The specification for the following methods mirrors the
|
||||
// specification of the same methods in the GSSContext interface, as
|
||||
// defined in RFC 2853.
|
||||
|
||||
public void requestLifetime(int lifetime) throws GSSException;
|
||||
|
||||
public void requestMutualAuth(boolean state) throws GSSException;
|
||||
|
||||
public void requestReplayDet(boolean state) throws GSSException;
|
||||
|
||||
public void requestSequenceDet(boolean state) throws GSSException;
|
||||
|
||||
public void requestCredDeleg(boolean state) throws GSSException;
|
||||
|
||||
public void requestAnonymity(boolean state) throws GSSException;
|
||||
|
||||
public void requestConf(boolean state) throws GSSException;
|
||||
|
||||
public void requestInteg(boolean state) throws GSSException;
|
||||
|
||||
public void requestDelegPolicy(boolean state) throws GSSException;
|
||||
|
||||
public void setChannelBinding(ChannelBinding cb) throws GSSException;
|
||||
|
||||
public boolean getCredDelegState();
|
||||
|
||||
public boolean getMutualAuthState();
|
||||
|
||||
public boolean getReplayDetState();
|
||||
|
||||
public boolean getSequenceDetState();
|
||||
|
||||
public boolean getAnonymityState();
|
||||
|
||||
public boolean getDelegPolicyState();
|
||||
|
||||
public boolean isTransferable() throws GSSException;
|
||||
|
||||
public boolean isProtReady();
|
||||
|
||||
public boolean isInitiator();
|
||||
|
||||
public boolean getConfState();
|
||||
|
||||
public boolean getIntegState();
|
||||
|
||||
public int getLifetime();
|
||||
|
||||
public boolean isEstablished();
|
||||
|
||||
public GSSNameSpi getSrcName() throws GSSException;
|
||||
|
||||
public GSSNameSpi getTargName() throws GSSException;
|
||||
|
||||
public Oid getMech() throws GSSException;
|
||||
|
||||
public GSSCredentialSpi getDelegCred() throws GSSException;
|
||||
|
||||
/**
|
||||
* Initiator context establishment call. This method may be
|
||||
* required to be called several times. A CONTINUE_NEEDED return
|
||||
* call indicates that more calls are needed after the next token
|
||||
* is received from the peer.
|
||||
* <p>
|
||||
* This method is called by the GSS-Framework when the application
|
||||
* calls the initSecContext method on the GSSContext implementation
|
||||
* that it has a reference to.
|
||||
* <p>
|
||||
* All overloaded forms of GSSContext.initSecContext() can be handled
|
||||
* with this mechanism level initSecContext. Since the output token
|
||||
* from this method is a fixed size, not exeedingly large, and a one
|
||||
* time deal, an overloaded form that takes an OutputStream has not
|
||||
* been defined. The GSS-Framwork can write the returned byte[] to any
|
||||
* application provided OutputStream. Similarly, any application input
|
||||
* int he form of byte arrays will be wrapped in an input stream by the
|
||||
* GSS-Framework and then passed here.
|
||||
* <p>
|
||||
* <strong>
|
||||
* The GSS-Framework will strip off the leading mechanism independent
|
||||
* GSS-API header. In other words, only the mechanism specific
|
||||
* inner-context token of RFC 2743 section 3.1 will be available on the
|
||||
* InputStream.
|
||||
* </strong>
|
||||
*
|
||||
* @param is contains the inner context token portion of the GSS token
|
||||
* received from the peer. On the first call to initSecContext, there
|
||||
* will be no token hence it will be ignored.
|
||||
* @param mechTokenSize the size of the inner context token as read by
|
||||
* the GSS-Framework from the mechanism independent GSS-API level
|
||||
* header.
|
||||
* @return any inner-context token required to be sent to the peer as
|
||||
* part of a GSS token. The mechanism should not add the mechanism
|
||||
* independent part of the token. The GSS-Framework will add that on
|
||||
* the way out.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] initSecContext(InputStream is, int mechTokenSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Acceptor's context establishment call. This method may be
|
||||
* required to be called several times. A CONTINUE_NEEDED return
|
||||
* call indicates that more calls are needed after the next token
|
||||
* is received from the peer.
|
||||
* <p>
|
||||
* This method is called by the GSS-Framework when the application
|
||||
* calls the acceptSecContext method on the GSSContext implementation
|
||||
* that it has a reference to.
|
||||
* <p>
|
||||
* All overloaded forms of GSSContext.acceptSecContext() can be handled
|
||||
* with this mechanism level acceptSecContext. Since the output token
|
||||
* from this method is a fixed size, not exeedingly large, and a one
|
||||
* time deal, an overloaded form that takes an OutputStream has not
|
||||
* been defined. The GSS-Framwork can write the returned byte[] to any
|
||||
* application provided OutputStream. Similarly, any application input
|
||||
* int he form of byte arrays will be wrapped in an input stream by the
|
||||
* GSS-Framework and then passed here.
|
||||
* <p>
|
||||
* <strong>
|
||||
* The GSS-Framework will strip off the leading mechanism independent
|
||||
* GSS-API header. In other words, only the mechanism specific
|
||||
* inner-context token of RFC 2743 section 3.1 will be available on the
|
||||
* InputStream.
|
||||
* </strong>
|
||||
*
|
||||
* @param is contains the inner context token portion of the GSS token
|
||||
* received from the peer.
|
||||
* @param mechTokenSize the size of the inner context token as read by
|
||||
* the GSS-Framework from the mechanism independent GSS-API level
|
||||
* header.
|
||||
* @return any inner-context token required to be sent to the peer as
|
||||
* part of a GSS token. The mechanism should not add the mechanism
|
||||
* independent part of the token. The GSS-Framework will add that on
|
||||
* the way out.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] acceptSecContext(InputStream is, int mechTokenSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Queries the context for largest data size to accommodate
|
||||
* the specified protection and for the token to remain less then
|
||||
* maxTokSize.
|
||||
*
|
||||
* @param qop the quality of protection that the context will be
|
||||
* asked to provide.
|
||||
* @param confReq a flag indicating whether confidentiality will be
|
||||
* requested or not
|
||||
* @param maxTokSize the maximum size of the output token
|
||||
* @return the maximum size for the input message that can be
|
||||
* provided to the wrap() method in order to guarantee that these
|
||||
* requirements are met.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Provides per-message token encapsulation.
|
||||
*
|
||||
* @param is the user-provided message to be protected
|
||||
* @param os the token to be sent to the peer. It includes
|
||||
* the message from <i>is</i> with the requested protection.
|
||||
* @param msgProp on input it contains the requested qop and
|
||||
* confidentiality state, on output, the applied values
|
||||
* @exception GSSException may be thrown
|
||||
* @see unwrap
|
||||
*/
|
||||
public void wrap(InputStream is, OutputStream os, MessageProp msgProp)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that want simplicity and don't care about buffer copies.
|
||||
*/
|
||||
public byte[] wrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies but either cannot use streams
|
||||
* or want to avoid them for whatever reason. (Say, they are using
|
||||
* block ciphers.)
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int wrap(byte inBuf[], int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* For apps that want to read from a specific application provided
|
||||
* buffer but want to write directly to the network stream.
|
||||
*/
|
||||
/*
|
||||
* Can be achieved by converting the input buffer to a
|
||||
* ByteInputStream. Provided to keep the API consistent
|
||||
* with unwrap.
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public void wrap(byte inBuf[], int offset, int len,
|
||||
OutputStream os, MessageProp msgProp)
|
||||
throws GSSException;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the message token previously encapsulated in the wrap
|
||||
* call.
|
||||
*
|
||||
* @param is the token from the peer
|
||||
* @param os unprotected message data
|
||||
* @param msgProp will contain the applied qop and confidentiality
|
||||
* of the input token and any informatory status values
|
||||
* @exception GSSException may be thrown
|
||||
* @see wrap
|
||||
*/
|
||||
public void unwrap(InputStream is, OutputStream os,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that want simplicity and don't care about buffer copies.
|
||||
*/
|
||||
public byte[] unwrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies but either cannot use streams
|
||||
* or want to avoid them for whatever reason. (Say, they are using
|
||||
* block ciphers.)
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int unwrap(byte inBuf[], int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies and want to read
|
||||
* straight from the network, but also want the output in a specific
|
||||
* application provided buffer, say to reduce buffer allocation or
|
||||
* subsequent copy.
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int unwrap(InputStream is,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Applies per-message integrity services.
|
||||
*
|
||||
* @param is the user-provided message
|
||||
* @param os the token to be sent to the peer along with the
|
||||
* message token. The message token <b>is not</b> encapsulated.
|
||||
* @param msgProp on input the desired QOP and output the applied QOP
|
||||
* @exception GSSException
|
||||
*/
|
||||
public void getMIC(InputStream is, OutputStream os,
|
||||
MessageProp msgProp)
|
||||
throws GSSException;
|
||||
|
||||
public byte[] getMIC(byte []inMsg, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* Checks the integrity of the supplied tokens.
|
||||
* This token was previously generated by getMIC.
|
||||
*
|
||||
* @param is token generated by getMIC
|
||||
* @param msgStr the message to check integrity for
|
||||
* @param mProp will contain the applied QOP and confidentiality
|
||||
* states of the token as well as any informatory status codes
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public void verifyMIC(InputStream is, InputStream msgStr,
|
||||
MessageProp mProp) throws GSSException;
|
||||
|
||||
public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
|
||||
byte[] inMsg, int msgOffset, int msgLen,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* Produces a token representing this context. After this call
|
||||
* the context will no longer be usable until an import is
|
||||
* performed on the returned token.
|
||||
*
|
||||
* @return exported context token
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] export() throws GSSException;
|
||||
|
||||
/**
|
||||
* Releases context resources and terminates the
|
||||
* context between 2 peer.
|
||||
*
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public void dispose() throws GSSException;
|
||||
|
||||
/**
|
||||
* Return the mechanism-specific attribute associated with (@code type}.
|
||||
*
|
||||
* @param type the type of the attribute requested
|
||||
* @return the attribute
|
||||
* @throws GSSException see {@link ExtendedGSSContext#inquireSecContext}
|
||||
* for details
|
||||
*/
|
||||
public Object inquireSecContext(InquireType type)
|
||||
throws GSSException;
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/security/jgss/spi/GSSCredentialSpi.java
Normal file
108
jdkSrc/jdk8/sun/security/jgss/spi/GSSCredentialSpi.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific credential
|
||||
* element. A GSSCredential is conceptually a container class of several
|
||||
* credential elements from different mechanisms.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
public interface GSSCredentialSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element and release
|
||||
* any system recourses and cryptographic information owned
|
||||
* by the credential.
|
||||
*
|
||||
* @exception GSSException with major codes NO_CRED and FAILURE
|
||||
*/
|
||||
public void dispose() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public GSSNameSpi getName() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException;
|
||||
|
||||
/**
|
||||
* Determines if this credential element can be used by a context
|
||||
* initiator.
|
||||
* @return true if it can be used for initiating contexts
|
||||
*/
|
||||
public boolean isInitiatorCredential() throws GSSException;
|
||||
|
||||
/**
|
||||
* Determines if this credential element can be used by a context
|
||||
* acceptor.
|
||||
* @return true if it can be used for accepting contexts
|
||||
*/
|
||||
public boolean isAcceptorCredential() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public Oid getMechanism();
|
||||
|
||||
/**
|
||||
* Impersonates another client.
|
||||
*
|
||||
* @param name the client to impersonate
|
||||
* @return the new credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException;
|
||||
}
|
||||
115
jdkSrc/jdk8/sun/security/jgss/spi/GSSNameSpi.java
Normal file
115
jdkSrc/jdk8/sun/security/jgss/spi/GSSNameSpi.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific name element. A
|
||||
* GSSName is conceptually a container class of several name elements from
|
||||
* different mechanisms.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface GSSNameSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Equals method for the GSSNameSpi objects.
|
||||
* If either name denotes an anonymous principal, the call should
|
||||
* return false.
|
||||
*
|
||||
* @param name to be compared with
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @exception GSSException with major codes of BAD_NAMETYPE,
|
||||
* BAD_NAME, FAILURE
|
||||
*/
|
||||
public boolean equals(GSSNameSpi name) throws GSSException;
|
||||
|
||||
/**
|
||||
* Compares this <code>GSSNameSpi</code> object to another Object
|
||||
* that might be a <code>GSSNameSpi</code>. The behaviour is exactly
|
||||
* the same as in {@link #equals(GSSNameSpi) equals} except that
|
||||
* no GSSException is thrown; instead, false will be returned in the
|
||||
* situation where an error occurs.
|
||||
*
|
||||
* @param another the object to be compared to
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @see #equals(GSSNameSpi)
|
||||
*/
|
||||
public boolean equals(Object another);
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSNameSpi.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode();
|
||||
|
||||
/**
|
||||
* Returns a flat name representation for this object. The name
|
||||
* format is defined in RFC 2078.
|
||||
*
|
||||
* @return the flat name representation for this object
|
||||
* @exception GSSException with major codes NAME_NOT_MN, BAD_NAME,
|
||||
* BAD_NAME, FAILURE.
|
||||
*/
|
||||
public byte[] export() throws GSSException;
|
||||
|
||||
|
||||
/**
|
||||
* Get the mechanism type that this NameElement corresponds to.
|
||||
*
|
||||
* @return the Oid of the mechanism type
|
||||
*/
|
||||
public Oid getMechanism();
|
||||
|
||||
/**
|
||||
* Returns a string representation for this name. The printed
|
||||
* name type can be obtained by calling getStringNameType().
|
||||
*
|
||||
* @return string form of this name
|
||||
* @see #getStringNameType()
|
||||
* @overrides Object#toString
|
||||
*/
|
||||
public String toString();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the oid describing the format of the printable name.
|
||||
*
|
||||
* @return the Oid for the format of the printed name
|
||||
*/
|
||||
public Oid getStringNameType();
|
||||
|
||||
/**
|
||||
* Indicates if this name object represents an Anonymous name.
|
||||
*/
|
||||
public boolean isAnonymousName();
|
||||
}
|
||||
214
jdkSrc/jdk8/sun/security/jgss/spi/MechanismFactory.java
Normal file
214
jdkSrc/jdk8/sun/security/jgss/spi/MechanismFactory.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by the factory class for every
|
||||
* plugin mechanism. The GSSManager locates an implementation of this
|
||||
* interface by querying the security providers installed on the
|
||||
* system. For a provider to support a mechanism defined by Oid x.y.z,
|
||||
* the provider master file would have to contain a mapping from the
|
||||
* property "GssApiMechanism.x.y.z" to an implementation class that serves
|
||||
* as the factory for that mechanism.
|
||||
* <p>
|
||||
* e.g., If a provider master file contained the a mapping from the
|
||||
* property "GssApiMechanism.1.2.840.113554.1.2.2" to the class name
|
||||
* "com.foo.krb5.Krb5GssFactory", then the GSS-API framework would assume
|
||||
* that com.foo.krb5.Krb5GssFactory implements the MechanismFactory
|
||||
* interface and that it can be used to obtain elements required by for
|
||||
* supporting this mechanism.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface MechanismFactory {
|
||||
|
||||
/**
|
||||
* Returns the Oid of the mechanism that this factory supports.
|
||||
* @return the Oid
|
||||
*/
|
||||
public Oid getMechanismOid();
|
||||
|
||||
/**
|
||||
* Returns the provider that this factory came from.
|
||||
* @return the provider
|
||||
*/
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Returns the GSS-API nametypes that this mechanism can
|
||||
* support. Having this method helps the GSS-Framework decide quickly
|
||||
* if a certain mechanism can be skipped when importing a name.
|
||||
* @return an array of the Oid's corresponding to the different GSS-API
|
||||
* nametypes supported
|
||||
* @see org.ietf.jgss.GSSName
|
||||
*/
|
||||
public Oid[] getNameTypes() throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a credential element for this mechanism to be included as
|
||||
* part of a GSSCredential implementation. A GSSCredential is
|
||||
* conceptually a container class of several credential elements from
|
||||
* different mechanisms. A GSS-API credential can be used either for
|
||||
* initiating GSS security contexts or for accepting them. This method
|
||||
* also accepts parameters that indicate what usage is expected and how
|
||||
* long the life of the credential should be. It is not necessary that
|
||||
* the mechanism honor the request for lifetime. An application will
|
||||
* always query an acquired GSSCredential to determine what lifetime it
|
||||
* got back.<p>
|
||||
*
|
||||
* <b>Not all mechanisms support the concept of one credential element
|
||||
* that can be used for both initiating and accepting a context. In the
|
||||
* event that an application requests usage INITIATE_AND_ACCEPT for a
|
||||
* credential from such a mechanism, the GSS framework will need to
|
||||
* obtain two different credential elements from the mechanism, one
|
||||
* that will have usage INITIATE_ONLY and another that will have usage
|
||||
* ACCEPT_ONLY. The mechanism will help the GSS-API realize this by
|
||||
* returning a credential element with usage INITIATE_ONLY or
|
||||
* ACCEPT_ONLY prompting it to make another call to
|
||||
* getCredentialElement, this time with the other usage mode. The
|
||||
* mechanism indicates the missing mode by returning a 0 lifetime for
|
||||
* it.</b>
|
||||
*
|
||||
* @param name the mechanism level name element for the entity whose
|
||||
* credential is desired. A null value indicates that a mechanism
|
||||
* dependent default choice is to be made.
|
||||
* @param initLifetime indicates the lifetime (in seconds) that is
|
||||
* requested for this credential to be used at the context initiator's
|
||||
* end. This value should be ignored if the usage is
|
||||
* ACCEPT_ONLY. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSCredential interface.
|
||||
* @param acceptLifetime indicates the lifetime (in seconds) that is
|
||||
* requested for this credential to be used at the context acceptor's
|
||||
* end. This value should be ignored if the usage is
|
||||
* INITIATE_ONLY. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSCredential interface.
|
||||
* @param usage One of the values GSSCredential.INIATE_ONLY,
|
||||
* GSSCredential.ACCEPT_ONLY, and GSSCredential.INITIATE_AND_ACCEPT.
|
||||
* @see org.ietf.jgss.GSSCredential
|
||||
* @throws GSSException if one of the error situations described in RFC
|
||||
* 2743 with the GSS_Acquire_Cred or GSS_Add_Cred calls occurs.
|
||||
*/
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime, int usage) throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a name element for this mechanism to be included as part of
|
||||
* a GSSName implementation. A GSSName is conceptually a container
|
||||
* class of several name elements from different mechanisms. A GSSName
|
||||
* can be created either with a String or with a sequence of
|
||||
* bytes. This factory method accepts the name in a String. Such a name
|
||||
* can generally be assumed to be printable and may be returned from
|
||||
* the name element's toString() method.
|
||||
*
|
||||
* @param nameStr a string containing the characters describing this
|
||||
* entity to the mechanism
|
||||
* @param nameType an Oid serving as a clue as to how the mechanism should
|
||||
* interpret the nameStr
|
||||
* @throws GSSException if any of the errors described in RFC 2743 for
|
||||
* the GSS_Import_Name or GSS_Canonicalize_Name calls occur.
|
||||
*/
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* This is a variation of the factory method that accepts a String for
|
||||
* the characters that make up the name. Usually the String characters
|
||||
* are assumed to be printable. The bytes passed in to this method have
|
||||
* to be converted to characters using some encoding of the mechanism's
|
||||
* choice. It is recommended that UTF-8 be used. (Note that UTF-8
|
||||
* preserves the encoding for 7-bit ASCII characters.)
|
||||
* <p>
|
||||
* An exported name will generally be passed in using this method.
|
||||
*
|
||||
* @param name the bytes describing this entity to the mechanism
|
||||
* @param nameType an Oid serving as a clue as to how the mechanism should
|
||||
* interpret the nameStr
|
||||
* @throws GSSException if any of the errors described in RFC 2743 for
|
||||
* the GSS_Import_Name or GSS_Canonicalize_Name calls occur.
|
||||
*/
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context for this mechanism so that it can be used
|
||||
* on the context initiator's side.
|
||||
*
|
||||
* @param peer the name element from this mechanism that represents the
|
||||
* peer
|
||||
* @param myInitiatorCred a credential element for the context
|
||||
* initiator obtained previously from this mechanism. The identity of
|
||||
* the context initiator can be obtained from this credential. Passing
|
||||
* a value of null here indicates that a default entity of the
|
||||
* mechanism's choice should be assumed to be the context initiator and
|
||||
* that default credentials should be applied.
|
||||
* @param lifetime the requested lifetime (in seconds) for the security
|
||||
* context. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSContext interface.
|
||||
* @throws GSSException if any of the errors described in RFC 2743 in
|
||||
* the GSS_Init_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred,
|
||||
int lifetime) throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context for this mechanism so thatit can be used
|
||||
* on the context acceptor's side.
|
||||
*
|
||||
* @param myAcceptorCred a credential element for the context acceptor
|
||||
* obtained previously from this mechanism. The identity of the context
|
||||
* acceptor cna be obtained from this credential. Passing a value of
|
||||
* null here indicates that tha default entity of the mechanism's
|
||||
* choice should be assumed to be the context acceptor and default
|
||||
* credentials should be applied.
|
||||
*
|
||||
* @throws GSSException if any of the errors described in RFC 2743 in
|
||||
* the GSS_Accept_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context from a previously exported (serialized)
|
||||
* security context. Note that this is different from Java
|
||||
* serialization and is defined at a mechanism level to interoperate
|
||||
* over the wire with non-Java implementations. Either the initiator or
|
||||
* the acceptor can export and then import a security context.
|
||||
* Implementations of mechanism contexts are not required to implement
|
||||
* exporting and importing.
|
||||
*
|
||||
* @param exportedContext the bytes representing this security context
|
||||
* @throws GSSException is any of the errors described in RFC 2743 in
|
||||
* the GSS_Import_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException;
|
||||
|
||||
}
|
||||
229
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenInit.java
Normal file
229
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenInit.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spnego;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Implements the SPNEGO NegTokenInit token
|
||||
* as specified in RFC 2478
|
||||
*
|
||||
* NegTokenInit ::= SEQUENCE {
|
||||
* mechTypes [0] MechTypeList OPTIONAL,
|
||||
* reqFlags [1] ContextFlags OPTIONAL,
|
||||
* mechToken [2] OCTET STRING OPTIONAL,
|
||||
* mechListMIC [3] OCTET STRING OPTIONAL
|
||||
* }
|
||||
*
|
||||
* MechTypeList ::= SEQUENCE OF MechType
|
||||
*
|
||||
* MechType::= OBJECT IDENTIFIER
|
||||
*
|
||||
* ContextFlags ::= BIT STRING {
|
||||
* delegFlag (0),
|
||||
* mutualFlag (1),
|
||||
* replayFlag (2),
|
||||
* sequenceFlag (3),
|
||||
* anonFlag (4),
|
||||
* confFlag (5),
|
||||
* integFlag (6)
|
||||
* }
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class NegTokenInit extends SpNegoToken {
|
||||
|
||||
// DER-encoded mechTypes
|
||||
private byte[] mechTypes = null;
|
||||
private Oid[] mechTypeList = null;
|
||||
|
||||
private BitArray reqFlags = null;
|
||||
private byte[] mechToken = null;
|
||||
private byte[] mechListMIC = null;
|
||||
|
||||
NegTokenInit(byte[] mechTypes, BitArray flags,
|
||||
byte[] token, byte[] mechListMIC)
|
||||
{
|
||||
super(NEG_TOKEN_INIT_ID);
|
||||
this.mechTypes = mechTypes;
|
||||
this.reqFlags = flags;
|
||||
this.mechToken = token;
|
||||
this.mechListMIC = mechListMIC;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to parse SPNEGO tokens
|
||||
public NegTokenInit(byte[] in) throws GSSException {
|
||||
super(NEG_TOKEN_INIT_ID);
|
||||
parseToken(in);
|
||||
}
|
||||
|
||||
final byte[] encode() throws GSSException {
|
||||
try {
|
||||
// create negInitToken
|
||||
DerOutputStream initToken = new DerOutputStream();
|
||||
|
||||
// DER-encoded mechTypes with CONTEXT 00
|
||||
if (mechTypes != null) {
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x00), mechTypes);
|
||||
}
|
||||
|
||||
// write context flags with CONTEXT 01
|
||||
if (reqFlags != null) {
|
||||
DerOutputStream flags = new DerOutputStream();
|
||||
flags.putUnalignedBitString(reqFlags);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x01), flags);
|
||||
}
|
||||
|
||||
// mechToken with CONTEXT 02
|
||||
if (mechToken != null) {
|
||||
DerOutputStream dataValue = new DerOutputStream();
|
||||
dataValue.putOctetString(mechToken);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x02), dataValue);
|
||||
}
|
||||
|
||||
// mechListMIC with CONTEXT 03
|
||||
if (mechListMIC != null) {
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"sending MechListMIC");
|
||||
}
|
||||
DerOutputStream mic = new DerOutputStream();
|
||||
mic.putOctetString(mechListMIC);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x03), mic);
|
||||
}
|
||||
|
||||
// insert in a SEQUENCE
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.write(DerValue.tag_Sequence, initToken);
|
||||
|
||||
return out.toByteArray();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenInit token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseToken(byte[] in) throws GSSException {
|
||||
try {
|
||||
DerValue der = new DerValue(in);
|
||||
// verify NegotiationToken type token
|
||||
if (!der.isContextSpecific((byte) NEG_TOKEN_INIT_ID)) {
|
||||
throw new IOException("SPNEGO NegoTokenInit : " +
|
||||
"did not have right token type");
|
||||
}
|
||||
DerValue tmp1 = der.data.getDerValue();
|
||||
if (tmp1.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("SPNEGO NegoTokenInit : " +
|
||||
"did not have the Sequence tag");
|
||||
}
|
||||
|
||||
// parse various fields if present
|
||||
int lastField = -1;
|
||||
while (tmp1.data.available() > 0) {
|
||||
DerValue tmp2 = tmp1.data.getDerValue();
|
||||
if (tmp2.isContextSpecific((byte)0x00)) {
|
||||
// get the DER-encoded sequence of mechTypes
|
||||
lastField = checkNextField(lastField, 0);
|
||||
DerInputStream mValue = tmp2.data;
|
||||
mechTypes = mValue.toByteArray();
|
||||
|
||||
// read all the mechTypes
|
||||
DerValue[] mList = mValue.getSequence(0);
|
||||
mechTypeList = new Oid[mList.length];
|
||||
ObjectIdentifier mech = null;
|
||||
for (int i = 0; i < mList.length; i++) {
|
||||
mech = mList[i].getOID();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"reading Mechanism Oid = " + mech);
|
||||
}
|
||||
mechTypeList[i] = new Oid(mech.toString());
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x01)) {
|
||||
lastField = checkNextField(lastField, 1);
|
||||
// received reqFlags, skip it
|
||||
} else if (tmp2.isContextSpecific((byte)0x02)) {
|
||||
lastField = checkNextField(lastField, 2);
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"reading Mech Token");
|
||||
}
|
||||
mechToken = tmp2.data.getOctetString();
|
||||
} else if (tmp2.isContextSpecific((byte)0x03)) {
|
||||
lastField = checkNextField(lastField, 3);
|
||||
if (!GSSUtil.useMSInterop()) {
|
||||
mechListMIC = tmp2.data.getOctetString();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"MechListMIC Token = " +
|
||||
getHexBytes(mechListMIC));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenInit token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
byte[] getMechTypes() {
|
||||
return mechTypes;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to find the mechs in SPNEGO tokens
|
||||
public Oid[] getMechTypeList() {
|
||||
return mechTypeList;
|
||||
}
|
||||
|
||||
BitArray getReqFlags() {
|
||||
return reqFlags;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to access the mech token portion of SPNEGO tokens
|
||||
public byte[] getMechToken() {
|
||||
return mechToken;
|
||||
}
|
||||
|
||||
byte[] getMechListMIC() {
|
||||
return mechListMIC;
|
||||
}
|
||||
|
||||
}
|
||||
200
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenTarg.java
Normal file
200
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenTarg.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spnego;
|
||||
|
||||
import java.io.*;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Implements the SPNEGO NegTokenTarg token
|
||||
* as specified in RFC 2478
|
||||
*
|
||||
* NegTokenTarg ::= SEQUENCE {
|
||||
* negResult [0] ENUMERATED {
|
||||
* accept_completed (0),
|
||||
* accept_incomplete (1),
|
||||
* reject (2) } OPTIONAL,
|
||||
* supportedMech [1] MechType OPTIONAL,
|
||||
* responseToken [2] OCTET STRING OPTIONAL,
|
||||
* mechListMIC [3] OCTET STRING OPTIONAL
|
||||
* }
|
||||
*
|
||||
* MechType::= OBJECT IDENTIFIER
|
||||
*
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class NegTokenTarg extends SpNegoToken {
|
||||
|
||||
private int negResult = 0;
|
||||
private Oid supportedMech = null;
|
||||
private byte[] responseToken = null;
|
||||
private byte[] mechListMIC = null;
|
||||
|
||||
NegTokenTarg(int result, Oid mech, byte[] token, byte[] mechListMIC)
|
||||
{
|
||||
super(NEG_TOKEN_TARG_ID);
|
||||
this.negResult = result;
|
||||
this.supportedMech = mech;
|
||||
this.responseToken = token;
|
||||
this.mechListMIC = mechListMIC;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to parse SPNEGO tokens
|
||||
public NegTokenTarg(byte[] in) throws GSSException {
|
||||
super(NEG_TOKEN_TARG_ID);
|
||||
parseToken(in);
|
||||
}
|
||||
|
||||
final byte[] encode() throws GSSException {
|
||||
try {
|
||||
// create negTargToken
|
||||
DerOutputStream targToken = new DerOutputStream();
|
||||
|
||||
// write the negotiated result with CONTEXT 00
|
||||
DerOutputStream result = new DerOutputStream();
|
||||
result.putEnumerated(negResult);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x00), result);
|
||||
|
||||
// supportedMech with CONTEXT 01
|
||||
if (supportedMech != null) {
|
||||
DerOutputStream mech = new DerOutputStream();
|
||||
byte[] mechType = supportedMech.getDER();
|
||||
mech.write(mechType);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x01), mech);
|
||||
}
|
||||
|
||||
// response Token with CONTEXT 02
|
||||
if (responseToken != null) {
|
||||
DerOutputStream rspToken = new DerOutputStream();
|
||||
rspToken.putOctetString(responseToken);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x02), rspToken);
|
||||
}
|
||||
|
||||
// mechListMIC with CONTEXT 03
|
||||
if (mechListMIC != null) {
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"sending MechListMIC");
|
||||
}
|
||||
DerOutputStream mic = new DerOutputStream();
|
||||
mic.putOctetString(mechListMIC);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x03), mic);
|
||||
}
|
||||
|
||||
// insert in a SEQUENCE
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.write(DerValue.tag_Sequence, targToken);
|
||||
|
||||
return out.toByteArray();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenTarg token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseToken(byte[] in) throws GSSException {
|
||||
try {
|
||||
DerValue der = new DerValue(in);
|
||||
// verify NegotiationToken type token
|
||||
if (!der.isContextSpecific((byte) NEG_TOKEN_TARG_ID)) {
|
||||
throw new IOException("SPNEGO NegoTokenTarg : " +
|
||||
"did not have the right token type");
|
||||
}
|
||||
DerValue tmp1 = der.data.getDerValue();
|
||||
if (tmp1.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("SPNEGO NegoTokenTarg : " +
|
||||
"did not have the Sequence tag");
|
||||
}
|
||||
|
||||
// parse various fields if present
|
||||
int lastField = -1;
|
||||
while (tmp1.data.available() > 0) {
|
||||
DerValue tmp2 = tmp1.data.getDerValue();
|
||||
if (tmp2.isContextSpecific((byte)0x00)) {
|
||||
lastField = checkNextField(lastField, 0);
|
||||
negResult = tmp2.data.getEnumerated();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: negotiated" +
|
||||
" result = " + getNegoResultString(negResult));
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x01)) {
|
||||
lastField = checkNextField(lastField, 1);
|
||||
ObjectIdentifier mech = tmp2.data.getOID();
|
||||
supportedMech = new Oid(mech.toString());
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"supported mechanism = " + supportedMech);
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x02)) {
|
||||
lastField = checkNextField(lastField, 2);
|
||||
responseToken = tmp2.data.getOctetString();
|
||||
} else if (tmp2.isContextSpecific((byte)0x03)) {
|
||||
lastField = checkNextField(lastField, 3);
|
||||
if (!GSSUtil.useMSInterop()) {
|
||||
mechListMIC = tmp2.data.getOctetString();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"MechListMIC Token = " +
|
||||
getHexBytes(mechListMIC));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenTarg token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
int getNegotiatedResult() {
|
||||
return negResult;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to find the supported mech in SPNEGO tokens
|
||||
public Oid getSupportedMech() {
|
||||
return supportedMech;
|
||||
}
|
||||
|
||||
byte[] getResponseToken() {
|
||||
return responseToken;
|
||||
}
|
||||
|
||||
byte[] getMechListMIC() {
|
||||
return mechListMIC;
|
||||
}
|
||||
}
|
||||
1244
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoContext.java
Normal file
1244
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoContext.java
Normal file
File diff suppressed because it is too large
Load Diff
96
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoCredElement.java
Normal file
96
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoCredElement.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.jgss.spnego;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.ProviderList;
|
||||
import sun.security.jgss.GSSCredentialImpl;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
|
||||
/**
|
||||
* This class is the cred element implementation for SPNEGO mech.
|
||||
* NOTE: The current implementation can only support one mechanism.
|
||||
* This should be changed once multi-mechanism support is needed.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
public class SpNegoCredElement implements GSSCredentialSpi {
|
||||
|
||||
private GSSCredentialSpi cred = null;
|
||||
|
||||
public SpNegoCredElement(GSSCredentialSpi cred) throws GSSException {
|
||||
this.cred = cred;
|
||||
}
|
||||
|
||||
Oid getInternalMech() {
|
||||
return cred.getMechanism();
|
||||
}
|
||||
|
||||
// Used by GSSUtil.populateCredentials()
|
||||
public GSSCredentialSpi getInternalCred() {
|
||||
return cred;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SpNegoMechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
cred.dispose();
|
||||
}
|
||||
|
||||
public GSSNameSpi getName() throws GSSException {
|
||||
return cred.getName();
|
||||
}
|
||||
|
||||
public int getInitLifetime() throws GSSException {
|
||||
return cred.getInitLifetime();
|
||||
}
|
||||
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return cred.getAcceptLifetime();
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return cred.isInitiatorCredential();
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return cred.isAcceptorCredential();
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return GSSUtil.GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
return cred.impersonate(name);
|
||||
}
|
||||
}
|
||||
193
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoMechFactory.java
Normal file
193
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoMechFactory.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spnego;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.jgss.krb5.Krb5MechFactory;
|
||||
import sun.security.jgss.krb5.Krb5InitCredential;
|
||||
import sun.security.jgss.krb5.Krb5AcceptCredential;
|
||||
import sun.security.jgss.krb5.Krb5NameElement;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* SpNego Mechanism plug in for JGSS
|
||||
* This is the properties object required by the JGSS framework.
|
||||
* All mechanism specific information is defined here.
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public final class SpNegoMechFactory implements MechanismFactory {
|
||||
|
||||
static final Provider PROVIDER =
|
||||
new sun.security.jgss.SunProvider();
|
||||
|
||||
static final Oid GSS_SPNEGO_MECH_OID =
|
||||
GSSUtil.createOid("1.3.6.1.5.5.2");
|
||||
|
||||
private static Oid[] nameTypes =
|
||||
new Oid[] { GSSName.NT_USER_NAME,
|
||||
GSSName.NT_HOSTBASED_SERVICE,
|
||||
GSSName.NT_EXPORT_NAME};
|
||||
|
||||
// The default underlying mech of SPNEGO, must not be SPNEGO itself.
|
||||
private static final Oid DEFAULT_SPNEGO_MECH_OID =
|
||||
ProviderList.DEFAULT_MECH_OID.equals(GSS_SPNEGO_MECH_OID)?
|
||||
GSSUtil.GSS_KRB5_MECH_OID:
|
||||
ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
// Use an instance of a GSSManager whose provider list
|
||||
// does not include native provider
|
||||
final GSSManagerImpl manager;
|
||||
final Oid[] availableMechs;
|
||||
|
||||
private static SpNegoCredElement getCredFromSubject(GSSNameSpi name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Vector<SpNegoCredElement> creds =
|
||||
GSSUtil.searchSubject(name, GSS_SPNEGO_MECH_OID,
|
||||
initiate, SpNegoCredElement.class);
|
||||
|
||||
SpNegoCredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
GSSCredentialSpi cred = result.getInternalCred();
|
||||
if (GSSUtil.isKerberosMech(cred.getMechanism())) {
|
||||
if (initiate) {
|
||||
Krb5InitCredential krbCred = (Krb5InitCredential) cred;
|
||||
Krb5MechFactory.checkInitCredPermission
|
||||
((Krb5NameElement) krbCred.getName());
|
||||
} else {
|
||||
Krb5AcceptCredential krbCred = (Krb5AcceptCredential) cred;
|
||||
Krb5MechFactory.checkAcceptCredPermission
|
||||
((Krb5NameElement) krbCred.getName(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public SpNegoMechFactory(GSSCaller caller) {
|
||||
manager = new GSSManagerImpl(caller, false);
|
||||
Oid[] mechs = manager.getMechs();
|
||||
availableMechs = new Oid[mechs.length-1];
|
||||
for (int i = 0, j = 0; i < mechs.length; i++) {
|
||||
// Skip SpNego mechanism
|
||||
if (!mechs[i].equals(GSS_SPNEGO_MECH_OID)) {
|
||||
availableMechs[j++] = mechs[i];
|
||||
}
|
||||
}
|
||||
// Move the preferred mech to first place
|
||||
for (int i=0; i<availableMechs.length; i++) {
|
||||
if (availableMechs[i].equals(DEFAULT_SPNEGO_MECH_OID)) {
|
||||
if (i != 0) {
|
||||
availableMechs[i] = availableMechs[0];
|
||||
availableMechs[0] = DEFAULT_SPNEGO_MECH_OID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return manager.getNameElement(
|
||||
nameStr, nameType, DEFAULT_SPNEGO_MECH_OID);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
return manager.getNameElement(name, nameType, DEFAULT_SPNEGO_MECH_OID);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime,
|
||||
int usage) throws GSSException {
|
||||
|
||||
SpNegoCredElement credElement = getCredFromSubject
|
||||
(name, (usage != GSSCredential.ACCEPT_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
// get CredElement for the default Mechanism
|
||||
credElement = new SpNegoCredElement
|
||||
(manager.getCredentialElement(name, initLifetime,
|
||||
acceptLifetime, null, usage));
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred, int lifetime)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
if (myInitiatorCred == null) {
|
||||
myInitiatorCred = getCredFromSubject(null, true);
|
||||
} else if (!(myInitiatorCred instanceof SpNegoCredElement)) {
|
||||
// convert to SpNegoCredElement
|
||||
SpNegoCredElement cred = new SpNegoCredElement(myInitiatorCred);
|
||||
return new SpNegoContext(this, peer, cred, lifetime);
|
||||
}
|
||||
return new SpNegoContext(this, peer, myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
if (myAcceptorCred == null) {
|
||||
myAcceptorCred = getCredFromSubject(null, false);
|
||||
} else if (!(myAcceptorCred instanceof SpNegoCredElement)) {
|
||||
// convert to SpNegoCredElement
|
||||
SpNegoCredElement cred = new SpNegoCredElement(myAcceptorCred);
|
||||
return new SpNegoContext(this, cred);
|
||||
}
|
||||
return new SpNegoContext(this, myAcceptorCred);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
return new SpNegoContext(this, exportedContext);
|
||||
}
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return PROVIDER;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() {
|
||||
// nameTypes is cloned in GSSManager.getNamesForMech
|
||||
return nameTypes;
|
||||
}
|
||||
}
|
||||
207
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoToken.java
Normal file
207
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoToken.java
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.spnego;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.util.*;
|
||||
import sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* Astract class for SPNEGO tokens.
|
||||
* Implementation is based on RFC 2478
|
||||
*
|
||||
* NegotiationToken ::= CHOICE {
|
||||
* negTokenInit [0] NegTokenInit,
|
||||
* negTokenTarg [1] NegTokenTarg }
|
||||
*
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
abstract class SpNegoToken extends GSSToken {
|
||||
|
||||
static final int NEG_TOKEN_INIT_ID = 0x00;
|
||||
static final int NEG_TOKEN_TARG_ID = 0x01;
|
||||
|
||||
static enum NegoResult {
|
||||
ACCEPT_COMPLETE,
|
||||
ACCEPT_INCOMPLETE,
|
||||
REJECT,
|
||||
};
|
||||
|
||||
private int tokenType;
|
||||
|
||||
// property
|
||||
static final boolean DEBUG = SpNegoContext.DEBUG;
|
||||
|
||||
/**
|
||||
* The object identifier corresponding to the SPNEGO GSS-API
|
||||
* mechanism.
|
||||
*/
|
||||
public static ObjectIdentifier OID;
|
||||
|
||||
static {
|
||||
try {
|
||||
OID = new ObjectIdentifier(SpNegoMechFactory.
|
||||
GSS_SPNEGO_MECH_OID.toString());
|
||||
} catch (IOException ioe) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates SPNEGO token of the specified type.
|
||||
*/
|
||||
protected SpNegoToken(int tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the individual encoded SPNEGO token
|
||||
*
|
||||
* @return the encoded token
|
||||
* @exception GSSException
|
||||
*/
|
||||
abstract byte[] encode() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the encoded SPNEGO token
|
||||
* Note: inserts the required CHOICE tags
|
||||
*
|
||||
* @return the encoded token
|
||||
* @exception GSSException
|
||||
*/
|
||||
byte[] getEncoded() throws IOException, GSSException {
|
||||
|
||||
// get the token encoded value
|
||||
DerOutputStream token = new DerOutputStream();
|
||||
token.write(encode());
|
||||
|
||||
// now insert the CHOICE
|
||||
switch (tokenType) {
|
||||
case NEG_TOKEN_INIT_ID:
|
||||
// Insert CHOICE of Negotiation Token
|
||||
DerOutputStream initToken = new DerOutputStream();
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) NEG_TOKEN_INIT_ID), token);
|
||||
return initToken.toByteArray();
|
||||
|
||||
case NEG_TOKEN_TARG_ID:
|
||||
// Insert CHOICE of Negotiation Token
|
||||
DerOutputStream targToken = new DerOutputStream();
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) NEG_TOKEN_TARG_ID), token);
|
||||
return targToken.toByteArray();
|
||||
default:
|
||||
return token.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SPNEGO token type
|
||||
*
|
||||
* @return the token type
|
||||
*/
|
||||
final int getType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the token type.
|
||||
*
|
||||
* @param tokenType the token type for which a string name is desired
|
||||
* @return the String name of this token type
|
||||
*/
|
||||
static String getTokenName(int type) {
|
||||
switch (type) {
|
||||
case NEG_TOKEN_INIT_ID:
|
||||
return "SPNEGO NegTokenInit";
|
||||
case NEG_TOKEN_TARG_ID:
|
||||
return "SPNEGO NegTokenTarg";
|
||||
default:
|
||||
return "SPNEGO Mechanism Token";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumerated type of the Negotiation result.
|
||||
*
|
||||
* @param result the negotiated result represented by integer
|
||||
* @return the enumerated type of Negotiated result
|
||||
*/
|
||||
static NegoResult getNegoResultType(int result) {
|
||||
switch (result) {
|
||||
case 0:
|
||||
return NegoResult.ACCEPT_COMPLETE;
|
||||
case 1:
|
||||
return NegoResult.ACCEPT_INCOMPLETE;
|
||||
case 2:
|
||||
return NegoResult.REJECT;
|
||||
default:
|
||||
// unknown - return optimistic result
|
||||
return NegoResult.ACCEPT_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the negotiation result.
|
||||
*
|
||||
* @param result the negotiated result
|
||||
* @return the String message of this negotiated result
|
||||
*/
|
||||
static String getNegoResultString(int result) {
|
||||
switch (result) {
|
||||
case 0:
|
||||
return "Accept Complete";
|
||||
case 1:
|
||||
return "Accept InComplete";
|
||||
case 2:
|
||||
return "Reject";
|
||||
default:
|
||||
return ("Unknown Negotiated Result: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the context tag in a sequence is in correct order. The "last"
|
||||
* value must be smaller than "current".
|
||||
* @param last the last tag seen
|
||||
* @param current the current tag
|
||||
* @return the current tag, used as the next value for last
|
||||
* @throws GSSException if there's a wrong order
|
||||
*/
|
||||
static int checkNextField(int last, int current) throws GSSException {
|
||||
if (last < current) {
|
||||
return current;
|
||||
} else {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SpNegoToken token : wrong order");
|
||||
}
|
||||
}
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSCredElement.java
Normal file
142
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSCredElement.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_cred_id_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
public class GSSCredElement implements GSSCredentialSpi {
|
||||
|
||||
private int usage;
|
||||
long pCred; // Pointer to the gss_cred_id_t structure
|
||||
private GSSNameElement name = null;
|
||||
private GSSLibStub cStub;
|
||||
|
||||
// Perform the necessary ServicePermission check on this cred
|
||||
void doServicePermCheck() throws GSSException {
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (isInitiatorCredential()) {
|
||||
String tgsName = Krb5Util.getTGSName(name);
|
||||
Krb5Util.checkServicePermission(tgsName, "initiate");
|
||||
}
|
||||
if (isAcceptorCredential() &&
|
||||
name != GSSNameElement.DEF_ACCEPTOR) {
|
||||
String krbName = name.getKrbName();
|
||||
Krb5Util.checkServicePermission(krbName, "accept");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct delegation cred using the actual context mech and srcName
|
||||
GSSCredElement(long pCredentials, GSSNameElement srcName, Oid mech)
|
||||
throws GSSException {
|
||||
pCred = pCredentials;
|
||||
cStub = GSSLibStub.getInstance(mech);
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
name = srcName;
|
||||
}
|
||||
|
||||
GSSCredElement(GSSNameElement name, int lifetime, int usage,
|
||||
GSSLibStub stub) throws GSSException {
|
||||
cStub = stub;
|
||||
this.usage = usage;
|
||||
|
||||
if (name != null) { // Could be GSSNameElement.DEF_ACCEPTOR
|
||||
this.name = name;
|
||||
doServicePermCheck();
|
||||
pCred = cStub.acquireCred(this.name.pName, lifetime, usage);
|
||||
} else {
|
||||
pCred = cStub.acquireCred(0, lifetime, usage);
|
||||
this.name = new GSSNameElement(cStub.getCredName(pCred), cStub);
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
name = null;
|
||||
if (pCred != 0) {
|
||||
pCred = cStub.releaseCred(pCred);
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameElement getName() throws GSSException {
|
||||
return (name == GSSNameElement.DEF_ACCEPTOR ?
|
||||
null : name);
|
||||
}
|
||||
|
||||
public int getInitLifetime() throws GSSException {
|
||||
if (isInitiatorCredential()) {
|
||||
return cStub.getCredTime(pCred);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
if (isAcceptorCredential()) {
|
||||
return cStub.getCredTime(pCred);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() {
|
||||
return (usage != GSSCredential.ACCEPT_ONLY);
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() {
|
||||
return (usage != GSSCredential.INITIATE_ONLY);
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
// No hex bytes available for native impl
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Not supported yet");
|
||||
}
|
||||
}
|
||||
126
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSLibStub.java
Normal file
126
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSLibStub.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import org.ietf.jgss.Oid;
|
||||
import org.ietf.jgss.GSSName;
|
||||
import org.ietf.jgss.ChannelBinding;
|
||||
import org.ietf.jgss.MessageProp;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
|
||||
/**
|
||||
* This class is essentially a JNI calling stub for all wrapper classes.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
class GSSLibStub {
|
||||
|
||||
private Oid mech;
|
||||
private long pMech;
|
||||
|
||||
/**
|
||||
* Initialization routine to dynamically load function pointers.
|
||||
*
|
||||
* @param lib library name to dlopen
|
||||
* @param debug set to true for reporting native debugging info
|
||||
* @return true if succeeded, false otherwise.
|
||||
*/
|
||||
static native boolean init(String lib, boolean debug);
|
||||
private static native long getMechPtr(byte[] oidDerEncoding);
|
||||
|
||||
// Miscellaneous routines
|
||||
static native Oid[] indicateMechs();
|
||||
native Oid[] inquireNamesForMech() throws GSSException;
|
||||
|
||||
// Name related routines
|
||||
native void releaseName(long pName);
|
||||
native long importName(byte[] name, Oid type);
|
||||
native boolean compareName(long pName1, long pName2);
|
||||
native long canonicalizeName(long pName);
|
||||
native byte[] exportName(long pName) throws GSSException;
|
||||
native Object[] displayName(long pName) throws GSSException;
|
||||
|
||||
// Credential related routines
|
||||
native long acquireCred(long pName, int lifetime, int usage)
|
||||
throws GSSException;
|
||||
native long releaseCred(long pCred);
|
||||
native long getCredName(long pCred);
|
||||
native int getCredTime(long pCred);
|
||||
native int getCredUsage(long pCred);
|
||||
|
||||
// Context related routines
|
||||
native NativeGSSContext importContext(byte[] interProcToken);
|
||||
native byte[] initContext(long pCred, long targetName, ChannelBinding cb,
|
||||
byte[] inToken, NativeGSSContext context);
|
||||
native byte[] acceptContext(long pCred, ChannelBinding cb,
|
||||
byte[] inToken, NativeGSSContext context);
|
||||
native long[] inquireContext(long pContext);
|
||||
native Oid getContextMech(long pContext);
|
||||
native long getContextName(long pContext, boolean isSrc);
|
||||
native int getContextTime(long pContext);
|
||||
native long deleteContext(long pContext);
|
||||
native int wrapSizeLimit(long pContext, int flags, int qop, int outSize);
|
||||
native byte[] exportContext(long pContext);
|
||||
native byte[] getMic(long pContext, int qop, byte[] msg);
|
||||
native void verifyMic(long pContext, byte[] token, byte[] msg,
|
||||
MessageProp prop) ;
|
||||
native byte[] wrap(long pContext, byte[] msg, MessageProp prop);
|
||||
native byte[] unwrap(long pContext, byte[] msgToken, MessageProp prop);
|
||||
|
||||
private static Hashtable<Oid, GSSLibStub>
|
||||
table = new Hashtable<Oid, GSSLibStub>(5);
|
||||
|
||||
static GSSLibStub getInstance(Oid mech) throws GSSException {
|
||||
GSSLibStub s = table.get(mech);
|
||||
if (s == null) {
|
||||
s = new GSSLibStub(mech);
|
||||
table.put(mech, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
private GSSLibStub(Oid mech) throws GSSException {
|
||||
SunNativeProvider.debug("Created GSSLibStub for mech " + mech);
|
||||
this.mech = mech;
|
||||
this.pMech = getMechPtr(mech.getDER());
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof GSSLibStub)) {
|
||||
return false;
|
||||
}
|
||||
return (mech.equals(((GSSLibStub) obj).getMech()));
|
||||
}
|
||||
public int hashCode() {
|
||||
return mech.hashCode();
|
||||
}
|
||||
Oid getMech() {
|
||||
return mech;
|
||||
}
|
||||
}
|
||||
295
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSNameElement.java
Normal file
295
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSNameElement.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import sun.security.krb5.Realm;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_name_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class GSSNameElement implements GSSNameSpi {
|
||||
|
||||
long pName = 0; // Pointer to the gss_name_t structure
|
||||
private String printableName;
|
||||
private Oid printableType;
|
||||
private GSSLibStub cStub;
|
||||
|
||||
static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement();
|
||||
|
||||
private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) {
|
||||
if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) {
|
||||
Oid[] supportedNTs = null;
|
||||
try {
|
||||
supportedNTs = stub.inquireNamesForMech();
|
||||
} catch (GSSException ge) {
|
||||
if (ge.getMajor() == GSSException.BAD_MECH &&
|
||||
GSSUtil.isSpNegoMech(stub.getMech())) {
|
||||
// Workaround known Heimdal issue and retry with KRB5
|
||||
try {
|
||||
stub = GSSLibStub.getInstance
|
||||
(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
supportedNTs = stub.inquireNamesForMech();
|
||||
} catch (GSSException ge2) {
|
||||
// Should never happen
|
||||
SunNativeProvider.debug("Name type list unavailable: " +
|
||||
ge2.getMajorString());
|
||||
}
|
||||
} else {
|
||||
SunNativeProvider.debug("Name type list unavailable: " +
|
||||
ge.getMajorString());
|
||||
}
|
||||
}
|
||||
if (supportedNTs != null) {
|
||||
for (int i = 0; i < supportedNTs.length; i++) {
|
||||
if (supportedNTs[i].equals(nameType)) return nameType;
|
||||
}
|
||||
// Special handling the specified name type
|
||||
SunNativeProvider.debug("Override " + nameType +
|
||||
" with mechanism default(null)");
|
||||
return null; // Use mechanism specific default
|
||||
}
|
||||
}
|
||||
return nameType;
|
||||
}
|
||||
|
||||
private GSSNameElement() {
|
||||
printableName = "<DEFAULT ACCEPTOR>";
|
||||
}
|
||||
|
||||
GSSNameElement(long pNativeName, GSSLibStub stub) throws GSSException {
|
||||
assert(stub != null);
|
||||
if (pNativeName == 0) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
// Note: pNativeName is assumed to be a MN.
|
||||
pName = pNativeName;
|
||||
cStub = stub;
|
||||
setPrintables();
|
||||
}
|
||||
|
||||
GSSNameElement(byte[] nameBytes, Oid nameType, GSSLibStub stub)
|
||||
throws GSSException {
|
||||
assert(stub != null);
|
||||
if (nameBytes == null) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
cStub = stub;
|
||||
byte[] name = nameBytes;
|
||||
|
||||
if (nameType != null) {
|
||||
// Special handling the specified name type if
|
||||
// necessary
|
||||
nameType = getNativeNameType(nameType, stub);
|
||||
|
||||
if (GSSName.NT_EXPORT_NAME.equals(nameType)) {
|
||||
// Need to add back the mech Oid portion (stripped
|
||||
// off by GSSNameImpl class prior to calling this
|
||||
// method) for "NT_EXPORT_NAME"
|
||||
byte[] mechBytes = null;
|
||||
DerOutputStream dout = new DerOutputStream();
|
||||
Oid mech = cStub.getMech();
|
||||
try {
|
||||
dout.putOID(new ObjectIdentifier(mech.toString()));
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, e);
|
||||
}
|
||||
mechBytes = dout.toByteArray();
|
||||
name = new byte[2 + 2 + mechBytes.length + 4 + nameBytes.length];
|
||||
int pos = 0;
|
||||
name[pos++] = 0x04;
|
||||
name[pos++] = 0x01;
|
||||
name[pos++] = (byte) (mechBytes.length>>>8);
|
||||
name[pos++] = (byte) mechBytes.length;
|
||||
System.arraycopy(mechBytes, 0, name, pos, mechBytes.length);
|
||||
pos += mechBytes.length;
|
||||
name[pos++] = (byte) (nameBytes.length>>>24);
|
||||
name[pos++] = (byte) (nameBytes.length>>>16);
|
||||
name[pos++] = (byte) (nameBytes.length>>>8);
|
||||
name[pos++] = (byte) nameBytes.length;
|
||||
System.arraycopy(nameBytes, 0, name, pos, nameBytes.length);
|
||||
}
|
||||
}
|
||||
pName = cStub.importName(name, nameType);
|
||||
setPrintables();
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null && !Realm.AUTODEDUCEREALM) {
|
||||
String krbName = getKrbName();
|
||||
int atPos = krbName.lastIndexOf('@');
|
||||
if (atPos != -1) {
|
||||
String atRealm = krbName.substring(atPos);
|
||||
// getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null
|
||||
if ((nameType == null
|
||||
|| nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
|
||||
&& new String(nameBytes).endsWith(atRealm)) {
|
||||
// Created from Kerberos name with realm, no need to check
|
||||
} else {
|
||||
try {
|
||||
sm.checkPermission(new ServicePermission(atRealm, "-"));
|
||||
} catch (SecurityException se) {
|
||||
// Do not chain the actual exception to hide info
|
||||
throw new GSSException(GSSException.FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SunNativeProvider.debug("Imported " + printableName + " w/ type " +
|
||||
printableType);
|
||||
}
|
||||
|
||||
private void setPrintables() throws GSSException {
|
||||
Object[] printables = null;
|
||||
printables = cStub.displayName(pName);
|
||||
assert((printables != null) && (printables.length == 2));
|
||||
printableName = (String) printables[0];
|
||||
assert(printableName != null);
|
||||
printableType = (Oid) printables[1];
|
||||
if (printableType == null) {
|
||||
printableType = GSSName.NT_USER_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to be public for GSSUtil.getSubject()
|
||||
public String getKrbName() throws GSSException {
|
||||
long mName = 0;
|
||||
GSSLibStub stub = cStub;
|
||||
if (!GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
stub = GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
mName = stub.canonicalizeName(pName);
|
||||
Object[] printables2 = stub.displayName(mName);
|
||||
stub.releaseName(mName);
|
||||
SunNativeProvider.debug("Got kerberized name: " + printables2[0]);
|
||||
return (String) printables2[0];
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public boolean equals(GSSNameSpi other) throws GSSException {
|
||||
if (!(other instanceof GSSNameElement)) {
|
||||
return false;
|
||||
}
|
||||
return cStub.compareName(pName, ((GSSNameElement)other).pName);
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof GSSNameElement)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return equals((GSSNameElement) other);
|
||||
} catch (GSSException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return new Long(pName).hashCode();
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
byte[] nameVal = cStub.exportName(pName);
|
||||
|
||||
// Need to strip off the mech Oid portion of the exported
|
||||
// bytes since GSSNameImpl class will subsequently add it.
|
||||
int pos = 0;
|
||||
if ((nameVal[pos++] != 0x04) ||
|
||||
(nameVal[pos++] != 0x01))
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
|
||||
int mechOidLen = (((0xFF & nameVal[pos++]) << 8) |
|
||||
(0xFF & nameVal[pos++]));
|
||||
ObjectIdentifier temp = null;
|
||||
try {
|
||||
DerInputStream din = new DerInputStream(nameVal, pos,
|
||||
mechOidLen);
|
||||
temp = new ObjectIdentifier(din);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME, e);
|
||||
}
|
||||
Oid mech2 = new Oid(temp.toString());
|
||||
assert(mech2.equals(getMechanism()));
|
||||
pos += mechOidLen;
|
||||
int mechPortionLen = (((0xFF & nameVal[pos++]) << 24) |
|
||||
((0xFF & nameVal[pos++]) << 16) |
|
||||
((0xFF & nameVal[pos++]) << 8) |
|
||||
(0xFF & nameVal[pos++]));
|
||||
if (mechPortionLen < 0) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
byte[] mechPortion = new byte[mechPortionLen];
|
||||
System.arraycopy(nameVal, pos, mechPortion, 0, mechPortionLen);
|
||||
return mechPortion;
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return printableName;
|
||||
}
|
||||
|
||||
public Oid getStringNameType() {
|
||||
return printableType;
|
||||
}
|
||||
|
||||
public boolean isAnonymousName() {
|
||||
return (GSSName.NT_ANONYMOUS.equals(printableType));
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (pName != 0) {
|
||||
cStub.releaseName(pName);
|
||||
pName = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/sun/security/jgss/wrapper/Krb5Util.java
Normal file
61
jdkSrc/jdk8/sun/security/jgss/wrapper/Krb5Util.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
|
||||
/**
|
||||
* This class is an utility class for Kerberos related stuff.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
class Krb5Util {
|
||||
|
||||
// Return the Kerberos TGS principal name using the domain
|
||||
// of the specified <code>name</code>
|
||||
static String getTGSName(GSSNameElement name)
|
||||
throws GSSException {
|
||||
String krbPrinc = name.getKrbName();
|
||||
int atIndex = krbPrinc.indexOf("@");
|
||||
String realm = krbPrinc.substring(atIndex + 1);
|
||||
StringBuffer buf = new StringBuffer("krbtgt/");
|
||||
buf.append(realm).append('@').append(realm);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Perform the Service Permission check using the specified
|
||||
// <code>target</code> and <code>action</code>
|
||||
static void checkServicePermission(String target, String action) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
SunNativeProvider.debug("Checking ServicePermission(" +
|
||||
target + ", " + action + ")");
|
||||
ServicePermission perm =
|
||||
new ServicePermission(target, action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
631
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSContext.java
Normal file
631
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSContext.java
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSHeader;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.jgss.spnego.NegTokenInit;
|
||||
import sun.security.jgss.spnego.NegTokenTarg;
|
||||
import javax.security.auth.kerberos.DelegationPermission;
|
||||
import com.sun.security.jgss.InquireType;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_ctx_id_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
class NativeGSSContext implements GSSContextSpi {
|
||||
|
||||
private static final int GSS_C_DELEG_FLAG = 1;
|
||||
private static final int GSS_C_MUTUAL_FLAG = 2;
|
||||
private static final int GSS_C_REPLAY_FLAG = 4;
|
||||
private static final int GSS_C_SEQUENCE_FLAG = 8;
|
||||
private static final int GSS_C_CONF_FLAG = 16;
|
||||
private static final int GSS_C_INTEG_FLAG = 32;
|
||||
private static final int GSS_C_ANON_FLAG = 64;
|
||||
private static final int GSS_C_PROT_READY_FLAG = 128;
|
||||
private static final int GSS_C_TRANS_FLAG = 256;
|
||||
|
||||
private static final int NUM_OF_INQUIRE_VALUES = 6;
|
||||
|
||||
private long pContext = 0; // Pointer to the gss_ctx_id_t structure
|
||||
private GSSNameElement srcName;
|
||||
private GSSNameElement targetName;
|
||||
private GSSCredElement cred;
|
||||
private boolean isInitiator;
|
||||
private boolean isEstablished;
|
||||
private Oid actualMech; // Assigned during context establishment
|
||||
|
||||
private ChannelBinding cb;
|
||||
private GSSCredElement delegatedCred;
|
||||
private int flags;
|
||||
private int lifetime = GSSCredential.DEFAULT_LIFETIME;
|
||||
private final GSSLibStub cStub;
|
||||
|
||||
private boolean skipDelegPermCheck;
|
||||
private boolean skipServicePermCheck;
|
||||
|
||||
// Retrieve the (preferred) mech out of SPNEGO tokens, i.e.
|
||||
// NegTokenInit & NegTokenTarg
|
||||
private static Oid getMechFromSpNegoToken(byte[] token,
|
||||
boolean isInitiator)
|
||||
throws GSSException {
|
||||
Oid mech = null;
|
||||
if (isInitiator) {
|
||||
GSSHeader header = null;
|
||||
try {
|
||||
header = new GSSHeader(new ByteArrayInputStream(token));
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
int negTokenLen = header.getMechTokenLength();
|
||||
byte[] negToken = new byte[negTokenLen];
|
||||
System.arraycopy(token, token.length-negTokenLen,
|
||||
negToken, 0, negToken.length);
|
||||
|
||||
NegTokenInit ntok = new NegTokenInit(negToken);
|
||||
if (ntok.getMechToken() != null) {
|
||||
Oid[] mechList = ntok.getMechTypeList();
|
||||
mech = mechList[0];
|
||||
}
|
||||
} else {
|
||||
NegTokenTarg ntok = new NegTokenTarg(token);
|
||||
mech = ntok.getSupportedMech();
|
||||
}
|
||||
return mech;
|
||||
}
|
||||
|
||||
// Perform the Service permission check
|
||||
private void doServicePermCheck() throws GSSException {
|
||||
if (System.getSecurityManager() != null) {
|
||||
String action = (isInitiator? "initiate" : "accept");
|
||||
// Need to check Service permission for accessing
|
||||
// initiator cred for SPNEGO during context establishment
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) && isInitiator
|
||||
&& !isEstablished) {
|
||||
if (srcName == null) {
|
||||
// Check by creating default initiator KRB5 cred
|
||||
GSSCredElement tempCred =
|
||||
new GSSCredElement(null, lifetime,
|
||||
GSSCredential.INITIATE_ONLY,
|
||||
GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID));
|
||||
tempCred.dispose();
|
||||
} else {
|
||||
String tgsName = Krb5Util.getTGSName(srcName);
|
||||
Krb5Util.checkServicePermission(tgsName, action);
|
||||
}
|
||||
}
|
||||
String targetStr = targetName.getKrbName();
|
||||
Krb5Util.checkServicePermission(targetStr, action);
|
||||
skipServicePermCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the Delegation permission check
|
||||
private void doDelegPermCheck() throws GSSException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
String targetStr = targetName.getKrbName();
|
||||
String tgsStr = Krb5Util.getTGSName(targetName);
|
||||
StringBuffer buf = new StringBuffer("\"");
|
||||
buf.append(targetStr).append("\" \"");
|
||||
buf.append(tgsStr).append('\"');
|
||||
String krbPrincPair = buf.toString();
|
||||
SunNativeProvider.debug("Checking DelegationPermission (" +
|
||||
krbPrincPair + ")");
|
||||
DelegationPermission perm =
|
||||
new DelegationPermission(krbPrincPair);
|
||||
sm.checkPermission(perm);
|
||||
skipDelegPermCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] retrieveToken(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] result = null;
|
||||
if (mechTokenLen != -1) {
|
||||
// Need to add back the GSS header for a complete GSS token
|
||||
SunNativeProvider.debug("Precomputed mechToken length: " +
|
||||
mechTokenLen);
|
||||
GSSHeader gssHeader = new GSSHeader
|
||||
(new ObjectIdentifier(cStub.getMech().toString()),
|
||||
mechTokenLen);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(600);
|
||||
|
||||
byte[] mechToken = new byte[mechTokenLen];
|
||||
int len = is.read(mechToken);
|
||||
assert(mechTokenLen == len);
|
||||
gssHeader.encode(baos);
|
||||
baos.write(mechToken);
|
||||
result = baos.toByteArray();
|
||||
} else {
|
||||
// Must be unparsed GSS token or SPNEGO's NegTokenTarg token
|
||||
assert(mechTokenLen == -1);
|
||||
DerValue dv = new DerValue(is);
|
||||
result = dv.toByteArray();
|
||||
}
|
||||
SunNativeProvider.debug("Complete Token length: " +
|
||||
result.length);
|
||||
return result;
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for context initiator
|
||||
NativeGSSContext(GSSNameElement peer, GSSCredElement myCred,
|
||||
int time, GSSLibStub stub) throws GSSException {
|
||||
if (peer == null) {
|
||||
throw new GSSException(GSSException.FAILURE, 1, "null peer");
|
||||
}
|
||||
cStub = stub;
|
||||
cred = myCred;
|
||||
targetName = peer;
|
||||
isInitiator = true;
|
||||
lifetime = time;
|
||||
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
doServicePermCheck();
|
||||
if (cred == null) {
|
||||
cred = new GSSCredElement(null, lifetime,
|
||||
GSSCredential.INITIATE_ONLY, cStub);
|
||||
}
|
||||
srcName = cred.getName();
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for context acceptor
|
||||
NativeGSSContext(GSSCredElement myCred, GSSLibStub stub)
|
||||
throws GSSException {
|
||||
cStub = stub;
|
||||
cred = myCred;
|
||||
|
||||
if (cred != null) targetName = cred.getName();
|
||||
|
||||
isInitiator = false;
|
||||
// Defer Service permission check for default acceptor cred
|
||||
// to acceptSecContext()
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech()) && targetName != null) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
|
||||
// srcName and potentially targetName (when myCred is null)
|
||||
// will be set in GSSLibStub.acceptContext(...)
|
||||
}
|
||||
|
||||
// Constructor for imported context
|
||||
NativeGSSContext(long pCtxt, GSSLibStub stub) throws GSSException {
|
||||
assert(pContext != 0);
|
||||
pContext = pCtxt;
|
||||
cStub = stub;
|
||||
|
||||
// Set everything except cred, cb, delegatedCred
|
||||
long[] info = cStub.inquireContext(pContext);
|
||||
if (info.length != NUM_OF_INQUIRE_VALUES) {
|
||||
throw new RuntimeException("Bug w/ GSSLibStub.inquireContext()");
|
||||
}
|
||||
srcName = new GSSNameElement(info[0], cStub);
|
||||
targetName = new GSSNameElement(info[1], cStub);
|
||||
isInitiator = (info[2] != 0);
|
||||
isEstablished = (info[3] != 0);
|
||||
flags = (int) info[4];
|
||||
lifetime = (int) info[5];
|
||||
|
||||
// Do Service Permission check when importing SPNEGO context
|
||||
// just to be safe
|
||||
Oid mech = cStub.getMech();
|
||||
if (GSSUtil.isSpNegoMech(mech) || GSSUtil.isKerberosMech(mech)) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public byte[] initSecContext(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
byte[] outToken = null;
|
||||
if ((!isEstablished) && (isInitiator)) {
|
||||
byte[] inToken = null;
|
||||
// Ignore the specified input stream on the first call
|
||||
if (pContext != 0) {
|
||||
inToken = retrieveToken(is, mechTokenLen);
|
||||
SunNativeProvider.debug("initSecContext=> inToken len=" +
|
||||
inToken.length);
|
||||
}
|
||||
|
||||
if (!getCredDelegState()) skipDelegPermCheck = true;
|
||||
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech()) && !skipDelegPermCheck) {
|
||||
doDelegPermCheck();
|
||||
}
|
||||
|
||||
long pCred = (cred == null? 0 : cred.pCred);
|
||||
outToken = cStub.initContext(pCred, targetName.pName,
|
||||
cb, inToken, this);
|
||||
SunNativeProvider.debug("initSecContext=> outToken len=" +
|
||||
(outToken == null ? 0 : outToken.length));
|
||||
|
||||
// Only inspect the token when the permission check
|
||||
// has not been performed
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) && outToken != null) {
|
||||
// WORKAROUND for SEAM bug#6287358
|
||||
actualMech = getMechFromSpNegoToken(outToken, true);
|
||||
|
||||
if (GSSUtil.isKerberosMech(actualMech)) {
|
||||
if (!skipServicePermCheck) doServicePermCheck();
|
||||
if (!skipDelegPermCheck) doDelegPermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
if (isEstablished) {
|
||||
if (srcName == null) {
|
||||
srcName = new GSSNameElement
|
||||
(cStub.getContextName(pContext, true), cStub);
|
||||
}
|
||||
if (cred == null) {
|
||||
cred = new GSSCredElement(srcName, lifetime,
|
||||
GSSCredential.INITIATE_ONLY,
|
||||
cStub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outToken;
|
||||
}
|
||||
|
||||
public byte[] acceptSecContext(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
byte[] outToken = null;
|
||||
if ((!isEstablished) && (!isInitiator)) {
|
||||
byte[] inToken = retrieveToken(is, mechTokenLen);
|
||||
SunNativeProvider.debug("acceptSecContext=> inToken len=" +
|
||||
inToken.length);
|
||||
long pCred = (cred == null? 0 : cred.pCred);
|
||||
outToken = cStub.acceptContext(pCred, cb, inToken, this);
|
||||
SunNativeProvider.debug("acceptSecContext=> outToken len=" +
|
||||
(outToken == null? 0 : outToken.length));
|
||||
|
||||
if (targetName == null) {
|
||||
targetName = new GSSNameElement
|
||||
(cStub.getContextName(pContext, false), cStub);
|
||||
// Replace the current default acceptor cred now that
|
||||
// the context acceptor name is available
|
||||
if (cred != null) cred.dispose();
|
||||
cred = new GSSCredElement(targetName, lifetime,
|
||||
GSSCredential.ACCEPT_ONLY, cStub);
|
||||
}
|
||||
|
||||
// Only inspect token when the permission check has not
|
||||
// been performed
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) &&
|
||||
(outToken != null) && !skipServicePermCheck) {
|
||||
if (GSSUtil.isKerberosMech(getMechFromSpNegoToken
|
||||
(outToken, false))) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
return outToken;
|
||||
}
|
||||
|
||||
public boolean isEstablished() {
|
||||
return isEstablished;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
srcName = null;
|
||||
targetName = null;
|
||||
cred = null;
|
||||
delegatedCred = null;
|
||||
if (pContext != 0) {
|
||||
pContext = cStub.deleteContext(pContext);
|
||||
pContext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getWrapSizeLimit(int qop, boolean confReq,
|
||||
int maxTokenSize)
|
||||
throws GSSException {
|
||||
return cStub.wrapSizeLimit(pContext, (confReq? 1:0), qop,
|
||||
maxTokenSize);
|
||||
}
|
||||
|
||||
public byte[] wrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] data = inBuf;
|
||||
if ((offset != 0) || (len != inBuf.length)) {
|
||||
data = new byte[len];
|
||||
System.arraycopy(inBuf, offset, data, 0, len);
|
||||
}
|
||||
return cStub.wrap(pContext, data, msgProp);
|
||||
}
|
||||
public void wrap(byte inBuf[], int offset, int len,
|
||||
OutputStream os, MessageProp msgProp)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] result = wrap(inBuf, offset, len, msgProp);
|
||||
os.write(result);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
public int wrap(byte[] inBuf, int inOffset, int len, byte[] outBuf,
|
||||
int outOffset, MessageProp msgProp)
|
||||
throws GSSException {
|
||||
byte[] result = wrap(inBuf, inOffset, len, msgProp);
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
public void wrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] data = new byte[inStream.available()];
|
||||
int length = inStream.read(data);
|
||||
byte[] token = wrap(data, 0, length, msgProp);
|
||||
outStream.write(token);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] unwrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp)
|
||||
throws GSSException {
|
||||
if ((offset != 0) || (len != inBuf.length)) {
|
||||
byte[] temp = new byte[len];
|
||||
System.arraycopy(inBuf, offset, temp, 0, len);
|
||||
return cStub.unwrap(pContext, temp, msgProp);
|
||||
} else {
|
||||
return cStub.unwrap(pContext, inBuf, msgProp);
|
||||
}
|
||||
}
|
||||
public int unwrap(byte[] inBuf, int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] result = null;
|
||||
if ((inOffset != 0) || (len != inBuf.length)) {
|
||||
byte[] temp = new byte[len];
|
||||
System.arraycopy(inBuf, inOffset, temp, 0, len);
|
||||
result = cStub.unwrap(pContext, temp, msgProp);
|
||||
} else {
|
||||
result = cStub.unwrap(pContext, inBuf, msgProp);
|
||||
}
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
public void unwrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] wrapped = new byte[inStream.available()];
|
||||
int wLength = inStream.read(wrapped);
|
||||
byte[] data = unwrap(wrapped, 0, wLength, msgProp);
|
||||
outStream.write(data);
|
||||
outStream.flush();
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public int unwrap(InputStream inStream,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] wrapped = null;
|
||||
int wLength = 0;
|
||||
try {
|
||||
wrapped = new byte[inStream.available()];
|
||||
wLength = inStream.read(wrapped);
|
||||
byte[] result = unwrap(wrapped, 0, wLength, msgProp);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
byte[] result = unwrap(wrapped, 0, wLength, msgProp);
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
|
||||
public byte[] getMIC(byte[] in, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
int qop = (msgProp == null? 0:msgProp.getQOP());
|
||||
byte[] inMsg = in;
|
||||
if ((offset != 0) || (len != in.length)) {
|
||||
inMsg = new byte[len];
|
||||
System.arraycopy(in, offset, inMsg, 0, len);
|
||||
}
|
||||
return cStub.getMic(pContext, qop, inMsg);
|
||||
}
|
||||
|
||||
public void getMIC(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
int length = 0;
|
||||
byte[] msg = new byte[inStream.available()];
|
||||
length = inStream.read(msg);
|
||||
|
||||
byte[] msgToken = getMIC(msg, 0, length, msgProp);
|
||||
if ((msgToken != null) && msgToken.length != 0) {
|
||||
outStream.write(msgToken);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void verifyMIC(byte[] inToken, int tOffset, int tLen,
|
||||
byte[] inMsg, int mOffset, int mLen,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] token = inToken;
|
||||
byte[] msg = inMsg;
|
||||
if ((tOffset != 0) || (tLen != inToken.length)) {
|
||||
token = new byte[tLen];
|
||||
System.arraycopy(inToken, tOffset, token, 0, tLen);
|
||||
}
|
||||
if ((mOffset != 0) || (mLen != inMsg.length)) {
|
||||
msg = new byte[mLen];
|
||||
System.arraycopy(inMsg, mOffset, msg, 0, mLen);
|
||||
}
|
||||
cStub.verifyMic(pContext, token, msg, msgProp);
|
||||
}
|
||||
|
||||
public void verifyMIC(InputStream tokStream, InputStream msgStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] msg = new byte[msgStream.available()];
|
||||
int mLength = msgStream.read(msg);
|
||||
byte[] tok = new byte[tokStream.available()];
|
||||
int tLength = tokStream.read(tok);
|
||||
verifyMIC(tok, 0, tLength, msg, 0, mLength, msgProp);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
byte[] result = cStub.exportContext(pContext);
|
||||
pContext = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void changeFlags(int flagMask, boolean isEnable) {
|
||||
if (isInitiator && pContext == 0) {
|
||||
if (isEnable) {
|
||||
flags |= flagMask;
|
||||
} else {
|
||||
flags &= ~flagMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void requestMutualAuth(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_MUTUAL_FLAG, state);
|
||||
}
|
||||
public void requestReplayDet(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_REPLAY_FLAG, state);
|
||||
}
|
||||
public void requestSequenceDet(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_SEQUENCE_FLAG, state);
|
||||
}
|
||||
public void requestCredDeleg(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_DELEG_FLAG, state);
|
||||
}
|
||||
public void requestAnonymity(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_ANON_FLAG, state);
|
||||
}
|
||||
public void requestConf(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_CONF_FLAG, state);
|
||||
}
|
||||
public void requestInteg(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_INTEG_FLAG, state);
|
||||
}
|
||||
public void requestDelegPolicy(boolean state) throws GSSException {
|
||||
// Not supported, ignore
|
||||
}
|
||||
public void requestLifetime(int lifetime) throws GSSException {
|
||||
if (isInitiator && pContext == 0) {
|
||||
this.lifetime = lifetime;
|
||||
}
|
||||
}
|
||||
public void setChannelBinding(ChannelBinding cb) throws GSSException {
|
||||
if (pContext == 0) {
|
||||
this.cb = cb;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkFlags(int flagMask) {
|
||||
return ((flags & flagMask) != 0);
|
||||
}
|
||||
public boolean getCredDelegState() {
|
||||
return checkFlags(GSS_C_DELEG_FLAG);
|
||||
}
|
||||
public boolean getMutualAuthState() {
|
||||
return checkFlags(GSS_C_MUTUAL_FLAG);
|
||||
}
|
||||
public boolean getReplayDetState() {
|
||||
return checkFlags(GSS_C_REPLAY_FLAG);
|
||||
}
|
||||
public boolean getSequenceDetState() {
|
||||
return checkFlags(GSS_C_SEQUENCE_FLAG);
|
||||
}
|
||||
public boolean getAnonymityState() {
|
||||
return checkFlags(GSS_C_ANON_FLAG);
|
||||
}
|
||||
public boolean isTransferable() throws GSSException {
|
||||
return checkFlags(GSS_C_TRANS_FLAG);
|
||||
}
|
||||
public boolean isProtReady() {
|
||||
return checkFlags(GSS_C_PROT_READY_FLAG);
|
||||
}
|
||||
public boolean getConfState() {
|
||||
return checkFlags(GSS_C_CONF_FLAG);
|
||||
}
|
||||
public boolean getIntegState() {
|
||||
return checkFlags(GSS_C_INTEG_FLAG);
|
||||
}
|
||||
public boolean getDelegPolicyState() {
|
||||
return false;
|
||||
}
|
||||
public int getLifetime() {
|
||||
return cStub.getContextTime(pContext);
|
||||
}
|
||||
public GSSNameSpi getSrcName() throws GSSException {
|
||||
return srcName;
|
||||
}
|
||||
public GSSNameSpi getTargName() throws GSSException {
|
||||
return targetName;
|
||||
}
|
||||
public Oid getMech() throws GSSException {
|
||||
if (isEstablished && actualMech != null) {
|
||||
return actualMech;
|
||||
} else {
|
||||
return cStub.getMech();
|
||||
}
|
||||
}
|
||||
public GSSCredentialSpi getDelegCred() throws GSSException {
|
||||
return delegatedCred;
|
||||
}
|
||||
public boolean isInitiator() {
|
||||
return isInitiator;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
|
||||
public Object inquireSecContext(InquireType type)
|
||||
throws GSSException {
|
||||
throw new GSSException(GSSException.UNAVAILABLE, -1,
|
||||
"Inquire type not supported.");
|
||||
}
|
||||
}
|
||||
183
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSFactory.java
Normal file
183
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSFactory.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.*;
|
||||
|
||||
/**
|
||||
* JGSS plugin for generic mechanisms provided through native GSS framework.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
*/
|
||||
|
||||
public final class NativeGSSFactory implements MechanismFactory {
|
||||
|
||||
GSSLibStub cStub = null;
|
||||
private final GSSCaller caller;
|
||||
|
||||
private GSSCredElement getCredFromSubject(GSSNameElement name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Oid mech = cStub.getMech();
|
||||
Vector<GSSCredElement> creds = GSSUtil.searchSubject
|
||||
(name, mech, initiate, GSSCredElement.class);
|
||||
|
||||
// If Subject is present but no native creds available
|
||||
if (creds != null && creds.isEmpty()) {
|
||||
if (GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
}
|
||||
|
||||
GSSCredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
result.doServicePermCheck();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public NativeGSSFactory(GSSCaller caller) {
|
||||
this.caller = caller;
|
||||
// Have to call setMech(Oid) explicitly before calling other
|
||||
// methods. Otherwise, NPE may be thrown unexpectantly
|
||||
}
|
||||
|
||||
public void setMech(Oid mech) throws GSSException {
|
||||
cStub = GSSLibStub.getInstance(mech);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] nameBytes =
|
||||
(nameStr == null ? null : nameStr.getBytes("UTF-8"));
|
||||
return new GSSNameElement(nameBytes, nameType, cStub);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// Shouldn't happen
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, uee);
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameElement(name, nameType, cStub);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime,
|
||||
int acceptLifetime,
|
||||
int usage)
|
||||
throws GSSException {
|
||||
GSSNameElement nname = null;
|
||||
if (name != null && !(name instanceof GSSNameElement)) {
|
||||
nname = (GSSNameElement)
|
||||
getNameElement(name.toString(), name.getStringNameType());
|
||||
} else nname = (GSSNameElement) name;
|
||||
|
||||
if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
|
||||
// Force separate acqusition of cred element since
|
||||
// MIT's impl does not correctly report NO_CRED error.
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
}
|
||||
|
||||
GSSCredElement credElement =
|
||||
getCredFromSubject(nname, (usage == GSSCredential.INITIATE_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
// No cred in the Subject
|
||||
if (usage == GSSCredential.INITIATE_ONLY) {
|
||||
credElement = new GSSCredElement(nname, initLifetime,
|
||||
usage, cStub);
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
if (nname == null) {
|
||||
nname = GSSNameElement.DEF_ACCEPTOR;
|
||||
}
|
||||
credElement = new GSSCredElement(nname, acceptLifetime,
|
||||
usage, cStub);
|
||||
} else {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unknown usage mode requested");
|
||||
}
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myCred,
|
||||
int lifetime)
|
||||
throws GSSException {
|
||||
if (peer == null) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
} else if (!(peer instanceof GSSNameElement)) {
|
||||
peer = (GSSNameElement)
|
||||
getNameElement(peer.toString(), peer.getStringNameType());
|
||||
}
|
||||
if (myCred == null) {
|
||||
myCred = getCredFromSubject(null, true);
|
||||
} else if (!(myCred instanceof GSSCredElement)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
return new NativeGSSContext((GSSNameElement) peer,
|
||||
(GSSCredElement) myCred,
|
||||
lifetime, cStub);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myCred)
|
||||
throws GSSException {
|
||||
if (myCred == null) {
|
||||
myCred = getCredFromSubject(null, false);
|
||||
} else if (!(myCred instanceof GSSCredElement)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
return new NativeGSSContext((GSSCredElement) myCred, cStub);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
return cStub.importContext(exportedContext);
|
||||
}
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() throws GSSException {
|
||||
return cStub.inquireNamesForMech();
|
||||
}
|
||||
}
|
||||
134
jdkSrc/jdk8/sun/security/jgss/wrapper/SunNativeProvider.java
Normal file
134
jdkSrc/jdk8/sun/security/jgss/wrapper/SunNativeProvider.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.jgss.wrapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import org.ietf.jgss.Oid;
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
/**
|
||||
* Defines the Sun NativeGSS provider for plugging in the
|
||||
* native GSS mechanisms to Java GSS.
|
||||
*
|
||||
* List of supported mechanisms depends on the local
|
||||
* machine configuration.
|
||||
*
|
||||
* @author Yu-Ching Valerie Peng
|
||||
*/
|
||||
|
||||
public final class SunNativeProvider extends Provider {
|
||||
|
||||
private static final long serialVersionUID = -238911724858694204L;
|
||||
|
||||
private static final String NAME = "SunNativeGSS";
|
||||
private static final String INFO = "Sun Native GSS provider";
|
||||
private static final String MF_CLASS =
|
||||
"sun.security.jgss.wrapper.NativeGSSFactory";
|
||||
private static final String LIB_PROP = "sun.security.jgss.lib";
|
||||
private static final String DEBUG_PROP = "sun.security.nativegss.debug";
|
||||
private static HashMap<String, String> MECH_MAP;
|
||||
static final Provider INSTANCE = new SunNativeProvider();
|
||||
static boolean DEBUG;
|
||||
static void debug(String message) {
|
||||
if (DEBUG) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
System.out.println(NAME + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
MECH_MAP =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<HashMap<String, String>>() {
|
||||
public HashMap<String, String> run() {
|
||||
DEBUG = Boolean.parseBoolean
|
||||
(System.getProperty(DEBUG_PROP));
|
||||
try {
|
||||
System.loadLibrary("j2gss");
|
||||
} catch (Error err) {
|
||||
debug("No j2gss library found!");
|
||||
if (DEBUG) err.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
String gssLibs[];
|
||||
String defaultLib = System.getProperty(LIB_PROP);
|
||||
if (defaultLib == null || defaultLib.trim().equals("")) {
|
||||
String osname = System.getProperty("os.name");
|
||||
if (osname.startsWith("SunOS")) {
|
||||
gssLibs = new String[]{ "libgss.so" };
|
||||
} else if (osname.startsWith("Linux")) {
|
||||
gssLibs = new String[]{
|
||||
"libgssapi.so",
|
||||
"libgssapi_krb5.so",
|
||||
"libgssapi_krb5.so.2",
|
||||
};
|
||||
} else if (osname.contains("OS X")) {
|
||||
gssLibs = new String[]{
|
||||
"libgssapi_krb5.dylib",
|
||||
"/usr/lib/sasl2/libgssapiv2.2.so",
|
||||
};
|
||||
} else if (osname.contains("Windows")) {
|
||||
// Full path needed, DLL is in jre/bin
|
||||
gssLibs = new String[]{ System.getProperty("java.home")
|
||||
+ "\\bin\\sspi_bridge.dll" };
|
||||
} else {
|
||||
gssLibs = new String[0];
|
||||
}
|
||||
} else {
|
||||
gssLibs = new String[]{ defaultLib };
|
||||
}
|
||||
for (String libName: gssLibs) {
|
||||
if (GSSLibStub.init(libName, DEBUG)) {
|
||||
debug("Loaded GSS library: " + libName);
|
||||
Oid[] mechs = GSSLibStub.indicateMechs();
|
||||
HashMap<String,String> map = new HashMap<>();
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
debug("Native MF for " + mechs[i]);
|
||||
map.put("GssApiMechanism." + mechs[i],
|
||||
MF_CLASS);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public SunNativeProvider() {
|
||||
/* We are the Sun NativeGSS provider */
|
||||
super(NAME, 1.8d, INFO);
|
||||
|
||||
if (MECH_MAP != null) {
|
||||
AccessController.doPrivileged(new PutAllAction(this, MECH_MAP));
|
||||
}
|
||||
}
|
||||
}
|
||||
41
jdkSrc/jdk8/sun/security/krb5/Asn1Exception.java
Normal file
41
jdkSrc/jdk8/sun/security/krb5/Asn1Exception.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
public class Asn1Exception extends KrbException {
|
||||
|
||||
private static final long serialVersionUID = 8291288984575084132L;
|
||||
|
||||
public Asn1Exception(int i) {
|
||||
super(i);
|
||||
}
|
||||
|
||||
}
|
||||
340
jdkSrc/jdk8/sun/security/krb5/Checksum.java
Normal file
340
jdkSrc/jdk8/sun/security/krb5/Checksum.java
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
import java.util.Arrays;
|
||||
import sun.security.util.*;
|
||||
import sun.security.krb5.internal.*;
|
||||
import sun.security.krb5.internal.crypto.*;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* This class encapsulates the concept of a Kerberos checksum.
|
||||
*/
|
||||
public class Checksum {
|
||||
|
||||
private int cksumType;
|
||||
private byte[] checksum;
|
||||
|
||||
// ----------------------------------------------+-------------+-----------
|
||||
// Checksum type |sumtype |checksum
|
||||
// |value | size
|
||||
// ----------------------------------------------+-------------+-----------
|
||||
public static final int CKSUMTYPE_NULL = 0; // 0
|
||||
public static final int CKSUMTYPE_CRC32 = 1; // 4
|
||||
public static final int CKSUMTYPE_RSA_MD4 = 2; // 16
|
||||
public static final int CKSUMTYPE_RSA_MD4_DES = 3; // 24
|
||||
public static final int CKSUMTYPE_DES_MAC = 4; // 16
|
||||
public static final int CKSUMTYPE_DES_MAC_K = 5; // 8
|
||||
public static final int CKSUMTYPE_RSA_MD4_DES_K = 6; // 16
|
||||
public static final int CKSUMTYPE_RSA_MD5 = 7; // 16
|
||||
public static final int CKSUMTYPE_RSA_MD5_DES = 8; // 24
|
||||
|
||||
// draft-ietf-krb-wg-crypto-07.txt
|
||||
public static final int CKSUMTYPE_HMAC_SHA1_DES3_KD = 12; // 20
|
||||
|
||||
// draft-raeburn-krb-rijndael-krb-07.txt
|
||||
public static final int CKSUMTYPE_HMAC_SHA1_96_AES128 = 15; // 96
|
||||
public static final int CKSUMTYPE_HMAC_SHA1_96_AES256 = 16; // 96
|
||||
|
||||
// draft-brezak-win2k-krb-rc4-hmac-04.txt
|
||||
public static final int CKSUMTYPE_HMAC_MD5_ARCFOUR = -138;
|
||||
|
||||
// default checksum type, -1 if not set
|
||||
static int CKSUMTYPE_DEFAULT;
|
||||
static int SAFECKSUMTYPE_DEFAULT;
|
||||
|
||||
private static boolean DEBUG = Krb5.DEBUG;
|
||||
static {
|
||||
initStatic();
|
||||
}
|
||||
|
||||
public static void initStatic() {
|
||||
String temp = null;
|
||||
Config cfg = null;
|
||||
try {
|
||||
cfg = Config.getInstance();
|
||||
temp = cfg.get("libdefaults", "default_checksum");
|
||||
if (temp != null) {
|
||||
CKSUMTYPE_DEFAULT = Config.getType(temp);
|
||||
} else {
|
||||
CKSUMTYPE_DEFAULT = -1;
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Exception in getting default checksum "+
|
||||
"value from the configuration. " +
|
||||
"No default checksum set.");
|
||||
exc.printStackTrace();
|
||||
}
|
||||
CKSUMTYPE_DEFAULT = -1;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
temp = cfg.get("libdefaults", "safe_checksum_type");
|
||||
if (temp != null)
|
||||
{
|
||||
SAFECKSUMTYPE_DEFAULT = Config.getType(temp);
|
||||
} else {
|
||||
SAFECKSUMTYPE_DEFAULT = -1;
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Exception in getting safe default " +
|
||||
"checksum value " +
|
||||
"from the configuration Setting. " +
|
||||
"No safe default checksum set.");
|
||||
exc.printStackTrace();
|
||||
}
|
||||
SAFECKSUMTYPE_DEFAULT = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Checksum using the raw data and type.
|
||||
*
|
||||
* This constructor is only used by Authenticator Checksum
|
||||
* {@link sun.security.jgss.krb5.InitialToken.OverloadedChecksum}
|
||||
* where the checksum type must be 0x8003
|
||||
* (see https://tools.ietf.org/html/rfc4121#section-4.1.1)
|
||||
* and checksum field/value is used to convey service flags,
|
||||
* channel bindings, and optional delegation information.
|
||||
* This special type does NOT have a {@link CksumType} and has its
|
||||
* own calculating and verification rules. It does has the same
|
||||
* ASN.1 encoding though.
|
||||
*
|
||||
* @param data the byte array of checksum.
|
||||
* @param new_cksumType the type of checksum.
|
||||
*/
|
||||
public Checksum(byte[] data, int new_cksumType) {
|
||||
cksumType = new_cksumType;
|
||||
checksum = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Checksum by calculating over the data using
|
||||
* the specified checksum type. If the checksum is unkeyed, key
|
||||
* and usage are ignored.
|
||||
*
|
||||
* @param new_cksumType the type of checksum. If set to -1, the
|
||||
* {@linkplain EType#checksumType() mandatory checksum type}
|
||||
* for the encryption type of {@code key} will be used
|
||||
* @param data the data that needs to be performed a checksum calculation on
|
||||
* @param key the key used by a keyed checksum
|
||||
* @param usage the usage used by a keyed checksum
|
||||
*/
|
||||
public Checksum(int new_cksumType, byte[] data,
|
||||
EncryptionKey key, int usage)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
if (new_cksumType == -1) {
|
||||
cksumType = EType.getInstance(key.getEType()).checksumType();
|
||||
} else {
|
||||
cksumType = new_cksumType;
|
||||
}
|
||||
checksum = CksumType.getInstance(cksumType).calculateChecksum(
|
||||
data, data.length, key.getBytes(), usage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the keyed checksum over the data passed in.
|
||||
*/
|
||||
public boolean verifyKeyedChecksum(byte[] data, EncryptionKey key, int usage)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
CksumType cksumEngine = CksumType.getInstance(cksumType);
|
||||
if (!cksumEngine.isKeyed()) {
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM);
|
||||
} else {
|
||||
return cksumEngine.verifyChecksum(
|
||||
data, data.length, key.getBytes(), checksum, usage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verifies the checksum over the data passed in. The checksum might
|
||||
* be a keyed or not.
|
||||
*
|
||||
* =============== ATTENTION! Use with care ==================
|
||||
* According to https://tools.ietf.org/html/rfc3961#section-6.1,
|
||||
* An unkeyed checksum should only be used "in limited circumstances
|
||||
* where the lack of a key does not provide a window for an attack,
|
||||
* preferably as part of an encrypted message".
|
||||
*/
|
||||
public boolean verifyAnyChecksum(byte[] data, EncryptionKey key, int usage)
|
||||
throws KdcErrException, KrbCryptoException {
|
||||
return CksumType.getInstance(cksumType).verifyChecksum(
|
||||
data, data.length, key.getBytes(), checksum, usage);
|
||||
}
|
||||
|
||||
boolean isEqual(Checksum cksum) throws KdcErrException {
|
||||
if (cksumType != cksum.cksumType) {
|
||||
return false;
|
||||
}
|
||||
return CksumType.isChecksumEqual(checksum, cksum.checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of Checksum from an ASN.1 encoded representation.
|
||||
* @param encoding a single DER-encoded value.
|
||||
* @exception Asn1Exception if an error occurs while decoding an ASN1
|
||||
* encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading encoded data.
|
||||
*
|
||||
*/
|
||||
public Checksum(DerValue encoding) throws Asn1Exception, IOException {
|
||||
DerValue der;
|
||||
if (encoding.getTag() != DerValue.tag_Sequence) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
der = encoding.getData().getDerValue();
|
||||
if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
|
||||
cksumType = der.getData().getBigInteger().intValue();
|
||||
}
|
||||
else
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
der = encoding.getData().getDerValue();
|
||||
if ((der.getTag() & (byte)0x1F) == (byte)0x01) {
|
||||
checksum = der.getData().getOctetString();
|
||||
}
|
||||
else
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
if (encoding.getData().available() > 0) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a Checksum object.
|
||||
* <pre>{@code
|
||||
* Checksum ::= SEQUENCE {
|
||||
* cksumtype [0] Int32,
|
||||
* checksum [1] OCTET STRING
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This definition reflects the Network Working Group RFC 4120
|
||||
* specification available at
|
||||
* <a href="http://www.ietf.org/rfc/rfc4120.txt">
|
||||
* http://www.ietf.org/rfc/rfc4120.txt</a>.
|
||||
* @return byte array of enocded Checksum.
|
||||
* @exception Asn1Exception if an error occurs while decoding an
|
||||
* ASN1 encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading
|
||||
* encoded data.
|
||||
*
|
||||
*/
|
||||
public byte[] asn1Encode() throws Asn1Exception, IOException {
|
||||
DerOutputStream bytes = new DerOutputStream();
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putInteger(BigInteger.valueOf(cksumType));
|
||||
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)0x00), temp);
|
||||
temp = new DerOutputStream();
|
||||
temp.putOctetString(checksum);
|
||||
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)0x01), temp);
|
||||
temp = new DerOutputStream();
|
||||
temp.write(DerValue.tag_Sequence, bytes);
|
||||
return temp.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse (unmarshal) a checksum object from a DER input stream. This form
|
||||
* parsing might be used when expanding a value which is part of
|
||||
* a constructed sequence and uses explicitly tagged type.
|
||||
*
|
||||
* @exception Asn1Exception if an error occurs while decoding an
|
||||
* ASN1 encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading
|
||||
* encoded data.
|
||||
* @param data the Der input stream value, which contains one or more
|
||||
* marshaled value.
|
||||
* @param explicitTag tag number.
|
||||
* @param optional indicates if this data field is optional
|
||||
* @return an instance of Checksum.
|
||||
*
|
||||
*/
|
||||
public static Checksum parse(DerInputStream data,
|
||||
byte explicitTag, boolean optional)
|
||||
throws Asn1Exception, IOException {
|
||||
|
||||
if ((optional) &&
|
||||
(((byte)data.peekByte() & (byte)0x1F) != explicitTag)) {
|
||||
return null;
|
||||
}
|
||||
DerValue der = data.getDerValue();
|
||||
if (explicitTag != (der.getTag() & (byte)0x1F)) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
} else {
|
||||
DerValue subDer = der.getData().getDerValue();
|
||||
return new Checksum(subDer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw bytes of the checksum, not in ASN.1 encoded form.
|
||||
*/
|
||||
public final byte[] getBytes() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public final int getType() {
|
||||
return cksumType;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Checksum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return isEqual((Checksum)obj);
|
||||
} catch (KdcErrException kee) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
int result = 17;
|
||||
result = 37 * result + cksumType;
|
||||
if (checksum != null) {
|
||||
result = 37 * result + Arrays.hashCode(checksum);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
1348
jdkSrc/jdk8/sun/security/krb5/Config.java
Normal file
1348
jdkSrc/jdk8/sun/security/krb5/Config.java
Normal file
File diff suppressed because it is too large
Load Diff
55
jdkSrc/jdk8/sun/security/krb5/Confounder.java
Normal file
55
jdkSrc/jdk8/sun/security/krb5/Confounder.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public final class Confounder {
|
||||
private static SecureRandom srand = new SecureRandom();
|
||||
|
||||
private Confounder() { // not instantiable
|
||||
}
|
||||
|
||||
public static byte[] bytes(int size) {
|
||||
byte[] data = new byte[size];
|
||||
srand.nextBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static int intValue() {
|
||||
return srand.nextInt();
|
||||
}
|
||||
|
||||
public static long longValue() {
|
||||
return srand.nextLong();
|
||||
}
|
||||
}
|
||||
585
jdkSrc/jdk8/sun/security/krb5/Credentials.java
Normal file
585
jdkSrc/jdk8/sun/security/krb5/Credentials.java
Normal file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
import sun.security.krb5.internal.*;
|
||||
import sun.security.krb5.internal.ccache.CredentialsCache;
|
||||
import sun.security.krb5.internal.crypto.EType;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* This class encapsulates the concept of a Kerberos service
|
||||
* credential. That includes a Kerberos ticket and an associated
|
||||
* session key.
|
||||
*/
|
||||
public class Credentials {
|
||||
|
||||
Ticket ticket;
|
||||
PrincipalName client;
|
||||
PrincipalName clientAlias;
|
||||
PrincipalName server;
|
||||
PrincipalName serverAlias;
|
||||
EncryptionKey key;
|
||||
TicketFlags flags;
|
||||
KerberosTime authTime;
|
||||
KerberosTime startTime;
|
||||
KerberosTime endTime;
|
||||
KerberosTime renewTill;
|
||||
HostAddresses cAddr;
|
||||
AuthorizationData authzData;
|
||||
private static boolean DEBUG = Krb5.DEBUG;
|
||||
private static CredentialsCache cache;
|
||||
static boolean alreadyLoaded = false;
|
||||
private static boolean alreadyTried = false;
|
||||
|
||||
private Credentials proxy = null;
|
||||
|
||||
public Credentials getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public Credentials setProxy(Credentials proxy) {
|
||||
this.proxy = proxy;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Read native ticket with session key type in the given list
|
||||
private static native Credentials acquireDefaultNativeCreds(int[] eTypes);
|
||||
|
||||
public Credentials(Ticket new_ticket,
|
||||
PrincipalName new_client,
|
||||
PrincipalName new_client_alias,
|
||||
PrincipalName new_server,
|
||||
PrincipalName new_server_alias,
|
||||
EncryptionKey new_key,
|
||||
TicketFlags new_flags,
|
||||
KerberosTime authTime,
|
||||
KerberosTime new_startTime,
|
||||
KerberosTime new_endTime,
|
||||
KerberosTime renewTill,
|
||||
HostAddresses cAddr,
|
||||
AuthorizationData authzData) {
|
||||
this(new_ticket, new_client, new_client_alias, new_server,
|
||||
new_server_alias, new_key, new_flags, authTime,
|
||||
new_startTime, new_endTime, renewTill, cAddr);
|
||||
this.authzData = authzData;
|
||||
}
|
||||
|
||||
public Credentials(Ticket new_ticket,
|
||||
PrincipalName new_client,
|
||||
PrincipalName new_client_alias,
|
||||
PrincipalName new_server,
|
||||
PrincipalName new_server_alias,
|
||||
EncryptionKey new_key,
|
||||
TicketFlags new_flags,
|
||||
KerberosTime authTime,
|
||||
KerberosTime new_startTime,
|
||||
KerberosTime new_endTime,
|
||||
KerberosTime renewTill,
|
||||
HostAddresses cAddr) {
|
||||
ticket = new_ticket;
|
||||
client = new_client;
|
||||
clientAlias = new_client_alias;
|
||||
server = new_server;
|
||||
serverAlias = new_server_alias;
|
||||
key = new_key;
|
||||
flags = new_flags;
|
||||
this.authTime = authTime;
|
||||
startTime = new_startTime;
|
||||
endTime = new_endTime;
|
||||
this.renewTill = renewTill;
|
||||
this.cAddr = cAddr;
|
||||
}
|
||||
|
||||
public Credentials(byte[] encoding,
|
||||
String client,
|
||||
String clientAlias,
|
||||
String server,
|
||||
String serverAlias,
|
||||
byte[] keyBytes,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
Date authTime,
|
||||
Date startTime,
|
||||
Date endTime,
|
||||
Date renewTill,
|
||||
InetAddress[] cAddrs) throws KrbException, IOException {
|
||||
this(new Ticket(encoding),
|
||||
new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL),
|
||||
(clientAlias == null? null : new PrincipalName(clientAlias,
|
||||
PrincipalName.KRB_NT_PRINCIPAL)),
|
||||
new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST),
|
||||
(serverAlias == null? null : new PrincipalName(serverAlias,
|
||||
PrincipalName.KRB_NT_SRV_INST)),
|
||||
new EncryptionKey(keyType, keyBytes),
|
||||
(flags == null? null: new TicketFlags(flags)),
|
||||
(authTime == null? null: new KerberosTime(authTime)),
|
||||
(startTime == null? null: new KerberosTime(startTime)),
|
||||
(endTime == null? null: new KerberosTime(endTime)),
|
||||
(renewTill == null? null: new KerberosTime(renewTill)),
|
||||
null); // caddrs are in the encoding at this point
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a service ticket for the specified service
|
||||
* principal. If the service ticket is not already available, it
|
||||
* obtains a new one from the KDC.
|
||||
*/
|
||||
/*
|
||||
public Credentials(Credentials tgt, PrincipalName service)
|
||||
throws KrbException {
|
||||
}
|
||||
*/
|
||||
|
||||
public final PrincipalName getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public final PrincipalName getClientAlias() {
|
||||
return clientAlias;
|
||||
}
|
||||
|
||||
public final PrincipalName getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public final PrincipalName getServerAlias() {
|
||||
return serverAlias;
|
||||
}
|
||||
|
||||
public final EncryptionKey getSessionKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public final Date getAuthTime() {
|
||||
if (authTime != null) {
|
||||
return authTime.toDate();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final Date getStartTime() {
|
||||
if (startTime != null)
|
||||
{
|
||||
return startTime.toDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final Date getEndTime() {
|
||||
if (endTime != null)
|
||||
{
|
||||
return endTime.toDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final Date getRenewTill() {
|
||||
if (renewTill != null)
|
||||
{
|
||||
return renewTill.toDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final boolean[] getFlags() {
|
||||
if (flags == null) // Can be in a KRB-CRED
|
||||
return null;
|
||||
return flags.toBooleanArray();
|
||||
}
|
||||
|
||||
public final InetAddress[] getClientAddresses() {
|
||||
|
||||
if (cAddr == null)
|
||||
return null;
|
||||
|
||||
return cAddr.getInetAddresses();
|
||||
}
|
||||
|
||||
public final byte[] getEncoded() {
|
||||
byte[] retVal = null;
|
||||
try {
|
||||
retVal = ticket.asn1Encode();
|
||||
} catch (Asn1Exception e) {
|
||||
if (DEBUG)
|
||||
System.out.println(e);
|
||||
} catch (IOException ioe) {
|
||||
if (DEBUG)
|
||||
System.out.println(ioe);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public boolean isForwardable() {
|
||||
return flags.get(Krb5.TKT_OPTS_FORWARDABLE);
|
||||
}
|
||||
|
||||
public boolean isRenewable() {
|
||||
return flags.get(Krb5.TKT_OPTS_RENEWABLE);
|
||||
}
|
||||
|
||||
public Ticket getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public TicketFlags getTicketFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public AuthorizationData getAuthzData() {
|
||||
return authzData;
|
||||
}
|
||||
/**
|
||||
* Checks if the service ticket returned by the KDC has the OK-AS-DELEGATE
|
||||
* flag set
|
||||
* @return true if OK-AS_DELEGATE flag is set, otherwise, return false.
|
||||
*/
|
||||
public boolean checkDelegate() {
|
||||
return flags.get(Krb5.TKT_OPTS_DELEGATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset TKT_OPTS_DELEGATE to false, called at credentials acquirement
|
||||
* when one of the cross-realm TGTs does not have the OK-AS-DELEGATE
|
||||
* flag set. This info must be preservable and restorable through
|
||||
* the Krb5Util.credsToTicket/ticketToCreds() methods so that even if
|
||||
* the service ticket is cached it still remembers the cross-realm
|
||||
* authentication result.
|
||||
*/
|
||||
public void resetDelegate() {
|
||||
flags.set(Krb5.TKT_OPTS_DELEGATE, false);
|
||||
}
|
||||
|
||||
public Credentials renew() throws KrbException, IOException {
|
||||
KDCOptions options = new KDCOptions();
|
||||
options.set(KDCOptions.RENEW, true);
|
||||
/*
|
||||
* Added here to pass KrbKdcRep.check:73
|
||||
*/
|
||||
options.set(KDCOptions.RENEWABLE, true);
|
||||
|
||||
return new KrbTgsReq(options,
|
||||
this,
|
||||
server,
|
||||
serverAlias,
|
||||
null, // from
|
||||
null, // till
|
||||
null, // rtime
|
||||
null, // eTypes
|
||||
cAddr,
|
||||
null,
|
||||
null,
|
||||
null).sendAndGetCreds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a TGT for the given client principal from a ticket cache.
|
||||
*
|
||||
* @param princ the client principal. A value of null means that the
|
||||
* default principal name in the credentials cache will be used.
|
||||
* @param ticketCache the path to the tickets file. A value
|
||||
* of null will be accepted to indicate that the default
|
||||
* path should be searched
|
||||
* @return the TGT credentials or null if none were found. If the tgt
|
||||
* expired, it is the responsibility of the caller to determine this.
|
||||
*/
|
||||
public static Credentials acquireTGTFromCache(PrincipalName princ,
|
||||
String ticketCache)
|
||||
throws KrbException, IOException {
|
||||
|
||||
if (ticketCache == null) {
|
||||
// The default ticket cache on Windows and Mac is not a file.
|
||||
String os = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("os.name"));
|
||||
if (os.toUpperCase(Locale.ENGLISH).startsWith("WINDOWS") ||
|
||||
os.toUpperCase(Locale.ENGLISH).contains("OS X")) {
|
||||
Credentials creds = acquireDefaultCreds();
|
||||
if (creds == null) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> Found no TGT's in LSA");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (princ != null) {
|
||||
if (creds.getClient().equals(princ)) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> Obtained TGT from LSA: "
|
||||
+ creds);
|
||||
}
|
||||
return creds;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> LSA contains TGT for "
|
||||
+ creds.getClient()
|
||||
+ " not "
|
||||
+ princ);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> Obtained TGT from LSA: "
|
||||
+ creds);
|
||||
}
|
||||
return creds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the appropriate cache. If ticketCache is null, it is the
|
||||
* default cache otherwise it is the cache filename contained in it.
|
||||
*/
|
||||
CredentialsCache ccache =
|
||||
CredentialsCache.getInstance(princ, ticketCache);
|
||||
|
||||
if (ccache == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Credentials tgtCred = ccache.getInitialCreds();
|
||||
|
||||
if (tgtCred == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (EType.isSupported(tgtCred.key.getEType())) {
|
||||
return tgtCred;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.out.println(
|
||||
">>> unsupported key type found the default TGT: " +
|
||||
tgtCred.key.getEType());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires default credentials.
|
||||
* <br>The possible locations for default credentials cache is searched in
|
||||
* the following order:
|
||||
* <ol>
|
||||
* <li> The directory and cache file name specified by "KRB5CCNAME" system.
|
||||
* property.
|
||||
* <li> The directory and cache file name specified by "KRB5CCNAME"
|
||||
* environment variable.
|
||||
* <li> A cache file named krb5cc_{user.name} at {user.home} directory.
|
||||
* </ol>
|
||||
* @return a <code>KrbCreds</code> object if the credential is found,
|
||||
* otherwise return null.
|
||||
*/
|
||||
|
||||
// this method is intentionally changed to not check if the caller's
|
||||
// principal name matches cache file's principal name.
|
||||
// It assumes that the GSS call has
|
||||
// the privilege to access the default cache file.
|
||||
|
||||
// This method is only called on Windows and Mac OS X, the native
|
||||
// acquireDefaultNativeCreds is also available on these platforms.
|
||||
public static synchronized Credentials acquireDefaultCreds() {
|
||||
Credentials result = null;
|
||||
|
||||
if (cache == null) {
|
||||
cache = CredentialsCache.getInstance();
|
||||
}
|
||||
if (cache != null) {
|
||||
Credentials temp = cache.getInitialCreds();
|
||||
if (temp != null) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KrbCreds found the default ticket"
|
||||
+ " granting ticket in credential cache.");
|
||||
}
|
||||
if (EType.isSupported(temp.key.getEType())) {
|
||||
result = temp;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.out.println(
|
||||
">>> unsupported key type found the default TGT: " +
|
||||
temp.key.getEType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
// Doesn't seem to be a default cache on this system or
|
||||
// TGT has unsupported encryption type
|
||||
|
||||
if (!alreadyTried) {
|
||||
// See if there's any native code to load
|
||||
try {
|
||||
ensureLoaded();
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Can not load credentials cache");
|
||||
e.printStackTrace();
|
||||
}
|
||||
alreadyTried = true;
|
||||
}
|
||||
}
|
||||
if (alreadyLoaded) {
|
||||
// There is some native code
|
||||
if (DEBUG) {
|
||||
System.out.println(">> Acquire default native Credentials");
|
||||
}
|
||||
try {
|
||||
result = acquireDefaultNativeCreds(
|
||||
EType.getDefaults("default_tkt_enctypes"));
|
||||
} catch (KrbException ke) {
|
||||
// when there is no default_tkt_enctypes.
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires credentials for a specified service using initial credential.
|
||||
* When the service has a different realm
|
||||
* from the initial credential, we do cross-realm authentication
|
||||
* - first, we use the current credential to get
|
||||
* a cross-realm credential from the local KDC, then use that
|
||||
* cross-realm credential to request service credential
|
||||
* from the foreigh KDC.
|
||||
*
|
||||
* @param service the name of service principal using format
|
||||
* components@realm
|
||||
* @param ccreds client's initial credential.
|
||||
* @exception IOException if an error occurs in reading the credentials
|
||||
* cache
|
||||
* @exception KrbException if an error occurs specific to Kerberos
|
||||
* @return a <code>Credentials</code> object.
|
||||
*/
|
||||
|
||||
public static Credentials acquireServiceCreds(String service,
|
||||
Credentials ccreds)
|
||||
throws KrbException, IOException {
|
||||
return CredentialsUtil.acquireServiceCreds(service, ccreds);
|
||||
}
|
||||
|
||||
public static Credentials acquireS4U2selfCreds(PrincipalName user,
|
||||
Credentials ccreds) throws KrbException, IOException {
|
||||
return CredentialsUtil.acquireS4U2selfCreds(user, ccreds);
|
||||
}
|
||||
|
||||
public static Credentials acquireS4U2proxyCreds(String service,
|
||||
Ticket second, PrincipalName client, Credentials ccreds)
|
||||
throws KrbException, IOException {
|
||||
return CredentialsUtil.acquireS4U2proxyCreds(
|
||||
service, second, client, ccreds);
|
||||
}
|
||||
|
||||
public CredentialsCache getCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints out debug info.
|
||||
*/
|
||||
public static void printDebug(Credentials c) {
|
||||
System.out.println(">>> DEBUG: ----Credentials----");
|
||||
System.out.println("\tclient: " + c.client.toString());
|
||||
if (c.clientAlias != null)
|
||||
System.out.println("\tclient alias: " + c.clientAlias.toString());
|
||||
System.out.println("\tserver: " + c.server.toString());
|
||||
if (c.serverAlias != null)
|
||||
System.out.println("\tserver alias: " + c.serverAlias.toString());
|
||||
System.out.println("\tticket: sname: " + c.ticket.sname.toString());
|
||||
if (c.startTime != null) {
|
||||
System.out.println("\tstartTime: " + c.startTime.getTime());
|
||||
}
|
||||
System.out.println("\tendTime: " + c.endTime.getTime());
|
||||
System.out.println(" ----Credentials end----");
|
||||
}
|
||||
|
||||
|
||||
static void ensureLoaded() {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void> () {
|
||||
public Void run() {
|
||||
if (System.getProperty("os.name").contains("OS X")) {
|
||||
System.loadLibrary("osxkrb5");
|
||||
} else {
|
||||
System.loadLibrary("w2k_lsa_auth");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
alreadyLoaded = true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer("Credentials:");
|
||||
buffer.append( "\n client=").append(client);
|
||||
if (clientAlias != null)
|
||||
buffer.append( "\n clientAlias=").append(clientAlias);
|
||||
buffer.append( "\n server=").append(server);
|
||||
if (serverAlias != null)
|
||||
buffer.append( "\n serverAlias=").append(serverAlias);
|
||||
if (authTime != null) {
|
||||
buffer.append("\n authTime=").append(authTime);
|
||||
}
|
||||
if (startTime != null) {
|
||||
buffer.append("\n startTime=").append(startTime);
|
||||
}
|
||||
buffer.append( "\n endTime=").append(endTime);
|
||||
buffer.append( "\n renewTill=").append(renewTill);
|
||||
buffer.append( "\n flags=").append(flags);
|
||||
buffer.append( "\nEType (skey)=").append(key.getEType());
|
||||
buffer.append( "\n (tkt key)=").append(ticket.encPart.eType);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() {
|
||||
return new sun.security.krb5.internal.ccache.Credentials(
|
||||
getClient(), getServer(),
|
||||
getSessionKey(),
|
||||
date2kt(getAuthTime()),
|
||||
date2kt(getStartTime()),
|
||||
date2kt(getEndTime()),
|
||||
date2kt(getRenewTill()),
|
||||
false,
|
||||
flags,
|
||||
new HostAddresses(getClientAddresses()),
|
||||
getAuthzData(),
|
||||
getTicket(),
|
||||
null);
|
||||
}
|
||||
|
||||
private static KerberosTime date2kt(Date d) {
|
||||
return d == null ? null : new KerberosTime(d);
|
||||
}
|
||||
}
|
||||
380
jdkSrc/jdk8/sun/security/krb5/EncryptedData.java
Normal file
380
jdkSrc/jdk8/sun/security/krb5/EncryptedData.java
Normal file
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
import sun.security.util.*;
|
||||
import sun.security.krb5.internal.crypto.*;
|
||||
import sun.security.krb5.internal.*;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* This class encapsulates Kerberos encrypted data. It allows
|
||||
* callers access to both the ASN.1 encoded form of the EncryptedData
|
||||
* type as well as the raw cipher text.
|
||||
*/
|
||||
|
||||
public class EncryptedData implements Cloneable {
|
||||
int eType;
|
||||
Integer kvno; // optional
|
||||
byte[] cipher;
|
||||
byte[] plain; // not part of ASN.1 encoding
|
||||
|
||||
// ----------------+-----------+----------+----------------+---------------
|
||||
// Encryption type |etype value|block size|minimum pad size|confounder size
|
||||
// ----------------+-----------+----------+----------------+---------------
|
||||
public static final int
|
||||
ETYPE_NULL = 0; // 1 0 0
|
||||
public static final int
|
||||
ETYPE_DES_CBC_CRC = 1; // 8 4 8
|
||||
public static final int
|
||||
ETYPE_DES_CBC_MD4 = 2; // 8 0 8
|
||||
public static final int
|
||||
ETYPE_DES_CBC_MD5 = 3; // 8 0 8
|
||||
|
||||
// draft-brezak-win2k-krb-rc4-hmac-04.txt
|
||||
public static final int
|
||||
ETYPE_ARCFOUR_HMAC = 23; // 1
|
||||
// NOTE: the exportable RC4-HMAC is not supported;
|
||||
// it is no longer a usable encryption type
|
||||
public static final int
|
||||
ETYPE_ARCFOUR_HMAC_EXP = 24; // 1
|
||||
|
||||
// draft-ietf-krb-wg-crypto-07.txt
|
||||
public static final int
|
||||
ETYPE_DES3_CBC_HMAC_SHA1_KD = 16; // 8 0 8
|
||||
|
||||
// draft-raeburn-krb-rijndael-krb-07.txt
|
||||
public static final int
|
||||
ETYPE_AES128_CTS_HMAC_SHA1_96 = 17; // 16 0 16
|
||||
public static final int
|
||||
ETYPE_AES256_CTS_HMAC_SHA1_96 = 18; // 16 0 16
|
||||
|
||||
/* used by self */
|
||||
private EncryptedData() {
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
EncryptedData new_encryptedData = new EncryptedData();
|
||||
new_encryptedData.eType = eType;
|
||||
if (kvno != null) {
|
||||
new_encryptedData.kvno = new Integer(kvno.intValue());
|
||||
}
|
||||
if (cipher != null) {
|
||||
new_encryptedData.cipher = new byte[cipher.length];
|
||||
System.arraycopy(cipher, 0, new_encryptedData.cipher,
|
||||
0, cipher.length);
|
||||
}
|
||||
return new_encryptedData;
|
||||
}
|
||||
|
||||
// Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
|
||||
public EncryptedData(
|
||||
int new_eType,
|
||||
Integer new_kvno,
|
||||
byte[] new_cipher) {
|
||||
eType = new_eType;
|
||||
kvno = new_kvno;
|
||||
cipher = new_cipher;
|
||||
}
|
||||
|
||||
/*
|
||||
// Not used.
|
||||
public EncryptedData(
|
||||
EncryptionKey key,
|
||||
byte[] plaintext)
|
||||
throws KdcErrException, KrbCryptoException {
|
||||
EType etypeEngine = EType.getInstance(key.getEType());
|
||||
cipher = etypeEngine.encrypt(plaintext, key.getBytes());
|
||||
eType = key.getEType();
|
||||
kvno = key.getKeyVersionNumber();
|
||||
}
|
||||
*/
|
||||
|
||||
// used in KrbApRep, KrbApReq, KrbAsReq, KrbCred, KrbPriv
|
||||
// Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
|
||||
public EncryptedData(
|
||||
EncryptionKey key,
|
||||
byte[] plaintext,
|
||||
int usage)
|
||||
throws KdcErrException, KrbCryptoException {
|
||||
EType etypeEngine = EType.getInstance(key.getEType());
|
||||
cipher = etypeEngine.encrypt(plaintext, key.getBytes(), usage);
|
||||
eType = key.getEType();
|
||||
kvno = key.getKeyVersionNumber();
|
||||
}
|
||||
|
||||
/*
|
||||
// Not used.
|
||||
public EncryptedData(
|
||||
EncryptionKey key,
|
||||
byte[] ivec,
|
||||
byte[] plaintext)
|
||||
throws KdcErrException, KrbCryptoException {
|
||||
EType etypeEngine = EType.getInstance(key.getEType());
|
||||
cipher = etypeEngine.encrypt(plaintext, key.getBytes(), ivec);
|
||||
eType = key.getEType();
|
||||
kvno = key.getKeyVersionNumber();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Not used.
|
||||
EncryptedData(
|
||||
StringBuffer password,
|
||||
byte[] plaintext)
|
||||
throws KdcErrException, KrbCryptoException {
|
||||
EncryptionKey key = new EncryptionKey(password);
|
||||
EType etypeEngine = EType.getInstance(key.getEType());
|
||||
cipher = etypeEngine.encrypt(plaintext, key.getBytes());
|
||||
eType = key.getEType();
|
||||
kvno = key.getKeyVersionNumber();
|
||||
}
|
||||
*/
|
||||
public byte[] decrypt(
|
||||
EncryptionKey key, int usage)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
if (eType != key.getEType()) {
|
||||
throw new KrbCryptoException(
|
||||
"EncryptedData is encrypted using keytype " +
|
||||
EType.toString(eType) +
|
||||
" but decryption key is of type " +
|
||||
EType.toString(key.getEType()));
|
||||
}
|
||||
|
||||
EType etypeEngine = EType.getInstance(eType);
|
||||
plain = etypeEngine.decrypt(cipher, key.getBytes(), usage);
|
||||
// The service ticket will be used in S4U2proxy request. Therefore
|
||||
// the raw ticket is still needed.
|
||||
//cipher = null;
|
||||
return etypeEngine.decryptedData(plain);
|
||||
}
|
||||
|
||||
/*
|
||||
// currently destructive on cipher
|
||||
// Not used.
|
||||
public byte[] decrypt(
|
||||
EncryptionKey key,
|
||||
byte[] ivec, int usage)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
// XXX check for matching eType and kvno here
|
||||
EType etypeEngine = EType.getInstance(eType);
|
||||
plain = etypeEngine.decrypt(cipher, key.getBytes(), ivec, usage);
|
||||
cipher = null;
|
||||
return etypeEngine.decryptedData(plain);
|
||||
}
|
||||
|
||||
// currently destructive on cipher
|
||||
// Not used.
|
||||
byte[] decrypt(StringBuffer password)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
EncryptionKey key = new EncryptionKey(password);
|
||||
// XXX check for matching eType here
|
||||
EType etypeEngine = EType.getInstance(eType);
|
||||
plain = etypeEngine.decrypt(cipher, key.getBytes());
|
||||
cipher = null;
|
||||
return etypeEngine.decryptedData(plain);
|
||||
}
|
||||
*/
|
||||
|
||||
private byte[] decryptedData() throws KdcErrException {
|
||||
if (plain != null) {
|
||||
EType etypeEngine = EType.getInstance(eType);
|
||||
return etypeEngine.decryptedData(plain);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of EncryptedData type.
|
||||
* @param encoding a single DER-encoded value.
|
||||
* @exception Asn1Exception if an error occurs while decoding an
|
||||
* ASN1 encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading encoded
|
||||
* data.
|
||||
*
|
||||
*/
|
||||
/* Used by self */
|
||||
private EncryptedData(DerValue encoding)
|
||||
throws Asn1Exception, IOException {
|
||||
|
||||
DerValue der = null;
|
||||
if (encoding.getTag() != DerValue.tag_Sequence) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
der = encoding.getData().getDerValue();
|
||||
if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
|
||||
eType = (der.getData().getBigInteger()).intValue();
|
||||
} else {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
|
||||
if ((encoding.getData().peekByte() & 0x1F) == 1) {
|
||||
der = encoding.getData().getDerValue();
|
||||
int i = (der.getData().getBigInteger()).intValue();
|
||||
kvno = new Integer(i);
|
||||
} else {
|
||||
kvno = null;
|
||||
}
|
||||
der = encoding.getData().getDerValue();
|
||||
if ((der.getTag() & (byte)0x1F) == (byte)0x02) {
|
||||
cipher = der.getData().getOctetString();
|
||||
} else {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
if (encoding.getData().available() > 0) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ASN.1 encoded EncryptedData type.
|
||||
*
|
||||
* <pre>{@code
|
||||
* EncryptedData ::= SEQUENCE {
|
||||
* etype [0] Int32 -- EncryptionType --,
|
||||
* kvno [1] UInt32 OPTIONAL,
|
||||
* cipher [2] OCTET STRING -- ciphertext
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This definition reflects the Network Working Group RFC 4120
|
||||
* specification available at
|
||||
* <a href="http://www.ietf.org/rfc/rfc4120.txt">
|
||||
* http://www.ietf.org/rfc/rfc4120.txt</a>.
|
||||
*
|
||||
* @return byte array of encoded EncryptedData object.
|
||||
* @exception Asn1Exception if an error occurs while decoding an
|
||||
* ASN1 encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading
|
||||
* encoded data.
|
||||
*
|
||||
*/
|
||||
public byte[] asn1Encode() throws Asn1Exception, IOException {
|
||||
DerOutputStream bytes = new DerOutputStream();
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putInteger(BigInteger.valueOf(this.eType));
|
||||
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)0x00), temp);
|
||||
temp = new DerOutputStream();
|
||||
if (kvno != null) {
|
||||
// encode as an unsigned integer (UInt32)
|
||||
temp.putInteger(BigInteger.valueOf(this.kvno.longValue()));
|
||||
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)0x01), temp);
|
||||
temp = new DerOutputStream();
|
||||
}
|
||||
temp.putOctetString(this.cipher);
|
||||
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
|
||||
(byte)0x02), temp);
|
||||
temp = new DerOutputStream();
|
||||
temp.write(DerValue.tag_Sequence, bytes);
|
||||
return temp.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse (unmarshal) an EncryptedData from a DER input stream. This form
|
||||
* parsing might be used when expanding a value which is part of
|
||||
* a constructed sequence and uses explicitly tagged type.
|
||||
*
|
||||
* @param data the Der input stream value, which contains one or more
|
||||
* marshaled value.
|
||||
* @param explicitTag tag number.
|
||||
* @param optional indicate if this data field is optional
|
||||
* @exception Asn1Exception if an error occurs while decoding an
|
||||
* ASN1 encoded data.
|
||||
* @exception IOException if an I/O error occurs while reading
|
||||
* encoded data.
|
||||
* @return an instance of EncryptedData.
|
||||
*
|
||||
*/
|
||||
public static EncryptedData parse(DerInputStream data,
|
||||
byte explicitTag,
|
||||
boolean optional)
|
||||
throws Asn1Exception, IOException {
|
||||
if ((optional) &&
|
||||
(((byte)data.peekByte() & (byte)0x1F) != explicitTag))
|
||||
return null;
|
||||
DerValue der = data.getDerValue();
|
||||
if (explicitTag != (der.getTag() & (byte)0x1F)) {
|
||||
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
|
||||
} else {
|
||||
DerValue subDer = der.getData().getDerValue();
|
||||
return new EncryptedData(subDer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset asn.1 data stream after decryption, remove redundant bytes.
|
||||
* @param data the decrypted data from decrypt().
|
||||
* @return the reset byte array which holds exactly one asn1 datum
|
||||
* including its tag and length.
|
||||
*
|
||||
*/
|
||||
public byte[] reset(byte[] data) {
|
||||
byte[] bytes = null;
|
||||
// for asn.1 encoded data, we use length field to
|
||||
// determine the data length and remove redundant paddings.
|
||||
if ((data[1] & 0xFF) < 128) {
|
||||
bytes = new byte[data[1] + 2];
|
||||
System.arraycopy(data, 0, bytes, 0, data[1] + 2);
|
||||
} else {
|
||||
if ((data[1] & 0xFF) > 128) {
|
||||
int len = data[1] & (byte)0x7F;
|
||||
int result = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1));
|
||||
}
|
||||
bytes = new byte[result + len + 2];
|
||||
System.arraycopy(data, 0, bytes, 0, result + len + 2);
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public int getEType() {
|
||||
return eType;
|
||||
}
|
||||
|
||||
public Integer getKeyVersionNumber() {
|
||||
return kvno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw cipher text bytes, not in ASN.1 encoding.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
return cipher;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user