X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=src%2Forg%2Fcacert%2Fgigi%2Fpages%2Faccount%2Fcerts%2FCertificateRequest.java;h=bae43d589e6fae2dab514b3b925872e6289856cf;hp=9efbceb53f4e7aa71197cb04ddc06f0047163052;hb=15c3594cf26458503691dc1993bdd6b414cf83c6;hpb=0fad27fa1dbd119648945ec77cd8e4a1b7965885 diff --git a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java index 9efbceb5..bae43d58 100644 --- a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java +++ b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java @@ -7,7 +7,6 @@ import java.security.PublicKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; -import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.HashSet; @@ -15,8 +14,6 @@ import java.util.LinkedHashSet; import java.util.Set; import java.util.TreeSet; -import javax.servlet.http.HttpServletRequest; - import org.cacert.gigi.GigiApiException; import org.cacert.gigi.crypto.SPKAC; import org.cacert.gigi.dbObjects.Certificate; @@ -27,11 +24,15 @@ import org.cacert.gigi.dbObjects.CertificateOwner; import org.cacert.gigi.dbObjects.CertificateProfile; import org.cacert.gigi.dbObjects.CertificateProfile.PropertyTemplate; import org.cacert.gigi.dbObjects.Digest; +import org.cacert.gigi.dbObjects.Group; import org.cacert.gigi.dbObjects.Organisation; import org.cacert.gigi.dbObjects.User; -import org.cacert.gigi.output.template.Scope; import org.cacert.gigi.output.template.SprintfCommand; +import org.cacert.gigi.util.AuthorizationContext; +import org.cacert.gigi.util.CAA; +import org.cacert.gigi.util.DomainAssessment; import org.cacert.gigi.util.PEM; +import org.cacert.gigi.util.RateLimit; import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs10.PKCS10; @@ -99,21 +100,19 @@ public class CertificateRequest { private String ou = ""; - private Organisation org = null; - - private User u; + private AuthorizationContext ctx; private String pDNS, pMail; - public CertificateRequest(User issuer, String csr) throws IOException, GeneralSecurityException, GigiApiException { - this(issuer, csr, (CertificateProfile) null); + public CertificateRequest(AuthorizationContext c, String csr) throws IOException, GeneralSecurityException, GigiApiException { + this(c, csr, (CertificateProfile) null); } - public CertificateRequest(User issuer, String csr, CertificateProfile cp) throws GeneralSecurityException, IOException, IOException { - u = issuer; + public CertificateRequest(AuthorizationContext ctx, String csr, CertificateProfile cp) throws GeneralSecurityException, IOException, IOException { + this.ctx = ctx; if (cp != null) { profile = cp; - } else if (u.getAssurancePoints() > 50) { + } else if (ctx.getActor().getAssurancePoints() > 50) { profile = CertificateProfile.getByName("client-a"); } byte[] data = PEM.decode("(NEW )?CERTIFICATE REQUEST", csr); @@ -162,7 +161,7 @@ public class CertificateRequest { } else if (c instanceof ExtendedKeyUsageExtension) { ExtendedKeyUsageExtension ekue = (ExtendedKeyUsageExtension) c; String appendix = ""; - if (u.getAssurancePoints() >= 50) { + if (ctx.getActor().getAssurancePoints() >= 50) { appendix = "-a"; } for (String s : ekue.getExtendedKeyUsage()) { @@ -198,8 +197,8 @@ public class CertificateRequest { this.csrType = CSRType.CSR; } - public CertificateRequest(User issuer, String spkac, String spkacChallenge) throws IOException, GigiApiException, GeneralSecurityException { - u = issuer; + public CertificateRequest(AuthorizationContext ctx, String spkac, String spkacChallenge) throws IOException, GigiApiException, GeneralSecurityException { + this.ctx = ctx; String cleanedSPKAC = spkac.replaceAll("[\r\n]", ""); byte[] data = Base64.getDecoder().decode(cleanedSPKAC); SPKAC parsed = new SPKAC(data); @@ -263,11 +262,11 @@ public class CertificateRequest { continue; } try { - SANType t = Certificate.SANType.valueOf(parts[0].toUpperCase()); + SANType t = Certificate.SANType.valueOf(parts[0].toUpperCase().trim()); if (t == null) { continue; } - parsedNames.add(new SubjectAlternateName(t, parts[1])); + parsedNames.add(new SubjectAlternateName(t, parts[1].trim())); } catch (IllegalArgumentException e) { // invalid enum type continue; @@ -284,12 +283,11 @@ public class CertificateRequest { return name; } - public Organisation getOrg() { - return org; - } - - public String getOu() { - return ou; + public synchronized String getOu() { + if (ctx.getTarget() instanceof Organisation) { + return ou; + } + throw new IllegalStateException(); } public Digest getSelectedDigest() { @@ -300,39 +298,24 @@ public class CertificateRequest { return profile; } - public synchronized boolean update(String nameIn, String hashAlg, String profileStr, String newOrgStr, String ou, String SANsStr, PrintWriter out, HttpServletRequest req) throws GigiApiException { + public synchronized boolean update(String nameIn, String hashAlg, String profileStr, String newOrgStr, String ou, String SANsStr) throws GigiApiException { GigiApiException error = new GigiApiException(); this.name = nameIn; if (hashAlg != null) { selectedDigest = Digest.valueOf(hashAlg); } this.profile = CertificateProfile.getByName(profileStr); - if (newOrgStr != null) { - Organisation neworg = Organisation.getById(Integer.parseInt(newOrgStr)); - if (neworg == null || u.getOrganisations().contains(neworg)) { - PropertyTemplate orga = profile.getTemplates().get("orga"); - if (orga != null) { - org = neworg; - } else { - org = null; - error.mergeInto(new GigiApiException("No organisations for this certificate profile.")); - } - } else { - error.mergeInto(new GigiApiException("Selected organisation is not part of your account.")); - } + if (ctx.getTarget() instanceof Organisation) { + this.ou = ou; } - this.ou = ou; - - if ( !this.profile.canBeIssuedBy(u)) { + if ( !this.profile.canBeIssuedBy(ctx.getTarget(), ctx.getActor())) { this.profile = CertificateProfile.getById(1); error.mergeInto(new GigiApiException("Certificate Profile is invalid.")); throw error; } - CertificateOwner owner = org != null ? org : u; - - verifySANs(error, profile, parseSANBox(SANsStr), owner); + verifySANs(error, profile, parseSANBox(SANsStr), ctx.getTarget(), ctx.getActor()); if ( !error.isEmpty()) { throw error; @@ -340,7 +323,7 @@ public class CertificateRequest { return true; } - private void verifySANs(GigiApiException error, CertificateProfile p, Set sANs2, CertificateOwner owner) { + private void verifySANs(GigiApiException error, CertificateProfile p, Set sANs2, CertificateOwner owner, User user) { Set filteredSANs = new LinkedHashSet<>(); PropertyTemplate domainTemp = p.getTemplates().get("domain"); PropertyTemplate emailTemp = p.getTemplates().get("email"); @@ -349,7 +332,14 @@ public class CertificateRequest { for (SubjectAlternateName san : sANs2) { if (san.getType() == SANType.DNS) { if (domainTemp != null && owner.isValidDomain(san.getName())) { - if (pDNS != null && !domainTemp.isMultiple()) { + boolean valid; + try { + DomainAssessment.checkCertifiableDomain(san.getName(), user.isInGroup(Group.CODESIGNING), false); + valid = true; + } catch (GigiApiException e) { + valid = false; + } + if ( !valid || !CAA.verifyDomainAccess(owner, p, san.getName()) || (pDNS != null && !domainTemp.isMultiple())) { // remove } else { if (pDNS == null) { @@ -372,10 +362,8 @@ public class CertificateRequest { } } } - HashMap vars = new HashMap<>(); - vars.put("SAN", san.getType().toString().toLowerCase() + ":" + san.getName()); - error.mergeInto(new GigiApiException(new Scope(new SprintfCommand(// - "The requested Subject alternate name \"{0}\" has been removed.", Arrays.asList("${SAN}")), vars))); + error.mergeInto(new GigiApiException(SprintfCommand.createSimple(// + "The requested subject alternate name (SAN) \"{0}\" has been removed.", san.getType().toString().toLowerCase() + ":" + san.getName()))); } SANs = filteredSANs; } @@ -390,7 +378,7 @@ public class CertificateRequest { PropertyTemplate emailTemp = profile.getTemplates().get("email"); PropertyTemplate nameTemp = profile.getTemplates().get("name"); PropertyTemplate wotUserTemp = profile.getTemplates().get("name=WoTUser"); - verifySANs(error, profile, SANs, org != null ? org : u); + verifySANs(error, profile, SANs, ctx.getTarget(), ctx.getActor()); // Ok, let's determine the CN // the CN is @@ -401,12 +389,12 @@ public class CertificateRequest { // primary domain. (domainTemp != null) String verifiedCN = null; - if (org == null) { - verifiedCN = verifyName(error, nameTemp, wotUserTemp, verifiedCN); - } else { + if (ctx.getTarget() instanceof Organisation) { if ( !name.equals("")) { verifiedCN = name; } + } else { + verifiedCN = verifyName(error, nameTemp, wotUserTemp, verifiedCN); } if (pDNS == null && domainTemp != null && domainTemp.isRequired()) { error.mergeInto(new GigiApiException("Server Certificates require a DNS name.")); @@ -432,7 +420,8 @@ public class CertificateRequest { } } - if (org != null) { + if (ctx.getTarget() instanceof Organisation) { + Organisation org = (Organisation) ctx.getTarget(); subject.put("O", org.getName()); subject.put("C", org.getState()); subject.put("ST", org.getProvince()); @@ -445,10 +434,21 @@ public class CertificateRequest { if ( !error.isEmpty()) { throw error; } - return new Certificate(u, subject, selectedDigest.toString(), // - this.csr, this.csrType, profile, SANs.toArray(new SubjectAlternateName[SANs.size()])); + try { + if (RATE_LIMIT.isLimitExceeded(Integer.toString(ctx.getActor().getId()))) { + throw new GigiApiException("Rate Limit Exceeded"); + } + return new Certificate(ctx.getTarget(), ctx.getActor(), subject, selectedDigest, // + this.csr, this.csrType, profile, SANs.toArray(new SubjectAlternateName[SANs.size()])); + } catch (IOException e) { + e.printStackTrace(); + } + return null; } + // 100 per 10 minutes + public static final RateLimit RATE_LIMIT = new RateLimit(100, 10 * 60 * 1000); + private String verifyName(GigiApiException error, PropertyTemplate nameTemp, PropertyTemplate wotUserTemp, String verifiedCN) { // real names, // possible configurations: name {y,null,?}, name=WoTUser {y,null} @@ -476,84 +476,96 @@ public class CertificateRequest { } else { error.mergeInto(new GigiApiException("Internal configuration error detected.")); } - if (name != null && u.isValidName(name)) { - if (realIsOK) { - verifiedCN = name; - } else { - error.mergeInto(new GigiApiException("Your real name is not allowed in this certificate.")); + if (ctx.getTarget() instanceof User) { + User u = (User) ctx.getTarget(); + if (name != null && u.isValidName(name)) { + if (realIsOK) { + verifiedCN = name; + } else { + error.mergeInto(new GigiApiException("Your real name is not allowed in this certificate.")); + if (defaultIsOK) { + name = DEFAULT_CN; + } else if (nullIsOK) { + name = ""; + } + } + } else if (name != null && name.equals(DEFAULT_CN)) { if (defaultIsOK) { - name = DEFAULT_CN; - } else if (nullIsOK) { - name = ""; + verifiedCN = name; + } else { + error.mergeInto(new GigiApiException("The default name is not allowed in this certificate.")); + if (nullIsOK) { + name = ""; + } else if (realIsOK) { + name = u.getPreferredName().toString(); + } } - } - } else if (name != null && name.equals(DEFAULT_CN)) { - if (defaultIsOK) { - verifiedCN = name; - } else { - error.mergeInto(new GigiApiException("The default name is not allowed in this certificate.")); + } else if (name == null || name.equals("")) { if (nullIsOK) { - name = ""; - } else if (realIsOK) { - name = u.getName().toString(); + verifiedCN = ""; + } else { + error.mergeInto(new GigiApiException("A name is required in this certificate.")); + if (defaultIsOK) { + name = DEFAULT_CN; + } else if (realIsOK) { + name = u.getPreferredName().toString(); + } } - } - } else if (name == null || name.equals("")) { - if (nullIsOK) { - verifiedCN = ""; } else { - error.mergeInto(new GigiApiException("A name is required in this certificate.")); - if (defaultIsOK) { + error.mergeInto(new GigiApiException("The name you entered was invalid.")); + + } + if (wotUserTemp != null) { + if ( !wotUserTemp.isRequired() || wotUserTemp.isMultiple()) { + error.mergeInto(new GigiApiException("Internal configuration error detected.")); + } + if ( !name.equals(DEFAULT_CN)) { name = DEFAULT_CN; - } else if (realIsOK) { - name = u.getName().toString(); + error.mergeInto(new GigiApiException("You may not change the name for this certificate type.")); + } else { + verifiedCN = DEFAULT_CN; } - } - } else { - error.mergeInto(new GigiApiException("The name you entered was invalid.")); - } - if (wotUserTemp != null) { - if ( !wotUserTemp.isRequired() || wotUserTemp.isMultiple()) { - error.mergeInto(new GigiApiException("Internal configuration error detected.")); - } - if ( !name.equals(DEFAULT_CN)) { - name = DEFAULT_CN; - error.mergeInto(new GigiApiException("You may not change the name for this certificate type.")); } else { - verifiedCN = DEFAULT_CN; - } + if (nameTemp != null) { + if (name.equals("")) { + if (nameTemp.isRequired()) { + // nothing, but required + name = DEFAULT_CN; + error.mergeInto(new GigiApiException("No name entered, but one was required.")); + } else { + // nothing and not required - } else { - if (nameTemp != null) { - if (name.equals("")) { - if (nameTemp.isRequired()) { - // nothing, but required - name = DEFAULT_CN; - error.mergeInto(new GigiApiException("No name entered, but one was required.")); + } + } else if (u.isValidName(name)) { + verifiedCN = name; } else { - // nothing and not required - + if (nameTemp.isRequired()) { + error.mergeInto(new GigiApiException("The name entered, does not match the details in your account. You cannot issue certificates with this name. Enter a name that matches the one that has been verified in your account, because a name is required for this certificate type.")); + } else if (name.equals(DEFAULT_CN)) { + verifiedCN = DEFAULT_CN; + } else { + name = DEFAULT_CN; + error.mergeInto(new GigiApiException("The name entered, does not match the details in your account. You cannot issue certificates with this name. Enter a name that matches the one that has been verified in your account or keep the default name.")); + } } - } else if (u.isValidName(name)) { - verifiedCN = name; } else { - if (nameTemp.isRequired()) { - error.mergeInto(new GigiApiException("The name entered, does not match the details in your account. You cannot issue certificates with this name. Enter a name that matches the one that has been assured in your account, because a name is required for this certificate type.")); - } else if (name.equals(DEFAULT_CN)) { - verifiedCN = DEFAULT_CN; - } else { - name = DEFAULT_CN; - error.mergeInto(new GigiApiException("The name entered, does not match the details in your account. You cannot issue certificates with this name. Enter a name that matches the one that has been assured in your account or keep the default name.")); + if ( !name.equals("")) { + name = ""; + error.mergeInto(new GigiApiException("No real name is included in this certificate. The real name, you entered will be ignored.")); } } + } + } else { + if (realIsOK) { + verifiedCN = name; } else { - if ( !name.equals("")) { - name = ""; - error.mergeInto(new GigiApiException("No real name is included in this certificate. The real name, you entered will be ignored.")); - } + verifiedCN = ""; + name = ""; + error.mergeInto(new GigiApiException("No real name is included in this certificate. The real name, you entered will be ignored.")); } } + return verifiedCN; } }