diff --git a/caps/idl/nsIPrincipal.idl b/caps/idl/nsIPrincipal.idl index 3ef3d7a0ce3..28c262e55ee 100644 --- a/caps/idl/nsIPrincipal.idl +++ b/caps/idl/nsIPrincipal.idl @@ -51,7 +51,7 @@ interface nsIURI; [ptr] native JSContext(JSContext); [ptr] native JSPrincipals(JSPrincipals); -[uuid(a67c4736-9a95-4ce1-9ffc-3f88c0913a34)] +[uuid(fb9ddeb9-26f9-46b8-85d5-3978aaee05aa)] interface nsIPrincipal : nsISerializable { /** @@ -68,17 +68,19 @@ interface nsIPrincipal : nsISerializable * Returns the security preferences associated with this principal. * prefBranch will be set to the pref branch to which these preferences * pertain. id is a pseudo-unique identifier, pertaining to either the - * certificateID or the origin. grantedList and deniedList are - * space-separated lists of capabilities which were explicitly granted - * or denied by a pref. + * fingerprint or the origin. subjectName is a name that identifies the + * entity this principal represents (may be empty). grantedList and + * deniedList are space-separated lists of capabilities which were + * explicitly granted or denied by a pref. */ void getPreferences(out string prefBranch, out string id, + out string subjectName, out string grantedList, out string deniedList); /** * Returns whether the other principal is equivalent to this principal. * Principals are considered equal if they are the same principal, - * they have the same origin, or have the same certificate ID + * they have the same origin, or have the same certificate fingerprint ID */ boolean equals(in nsIPrincipal other); @@ -99,9 +101,18 @@ interface nsIPrincipal : nsISerializable // XXXcaa should this be here? The script security manager is the only // thing that should care about this. Wouldn't storing this data in one // of the hashtables in nsScriptSecurityManager be better? + // XXXbz why is this writable? Who should have write access to this? What + // happens if this principal is in our hashtable and we pass it out of the + // security manager and someone writes to this field? Especially if they + // write garbage? If we need to give someone other than the security + // manager a way to set this (which I question, since it can increase the + // permissions of a page) it should be a |void clearSecurityPolicy()| + // method. attribute voidPtr securityPolicy; // XXXcaa probably should be turned into {get|set}CapabilityFlags + // XXXbz again, what if this lives in our hashtable and someone + // messes with it? Is that OK? short canEnableCapability(in string capability); void setCanEnableCapability(in string capability, in short canEnable); boolean isCapabilityEnabled(in string capability, in voidPtr annotation); @@ -143,14 +154,18 @@ interface nsIPrincipal : nsISerializable */ // XXXcaa kaie says this may not be unique. We should probably // consider using something else for this.... - readonly attribute string certificateID; + readonly attribute AUTF8String fingerprint; /** - * The common name for the certificate. - * This pertains to the certificate authority organization. + * The pretty name for the certificate. This sort of (but not really) + * identifies the subject of the certificate (the entity that stands behind + * the certificate). Note that this may be empty; prefer to get the + * certificate itself and get this information from it, since that may + * provide more information. + * * Throws if there is no certificate associated with this principal. */ - attribute string commonName; + readonly attribute AUTF8String prettyName; /** * Returns whether the other principal is equal to or weaker than this @@ -171,4 +186,21 @@ interface nsIPrincipal : nsISerializable * release; note that nsIPrincipal is unfrozen, not slated to be frozen. */ boolean subsumes(in nsIPrincipal other); + + /** + * The subject name for the certificate. This actually identifies the + * subject of the certificate. This may well not be a string that would + * mean much to a typical user on its own (e.g. it may have a number of + * different names all concatenated together with some information on what + * they mean in between). + * + * Throws if there is no certificate associated with this principal. + */ + readonly attribute AUTF8String subjectName; + + /** + * The certificate associated with this principal, if any. If there isn't + * one, this will return null. Getting this attribute never throws. + */ + readonly attribute nsISupports certificate; }; diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index fa0180e3da3..266a50bae0a 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -41,7 +41,7 @@ interface nsIURI; -[scriptable, uuid(463eb1fa-9dac-4ca7-826f-1fc921971d3a)] +[scriptable, uuid(f4d74511-2b2d-4a14-a3e4-a392ac5ac3ff)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// @@ -161,9 +161,19 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager [noscript] nsIPrincipal getSystemPrincipal(); /** - * Return a principal with the specified certificate ID and codebase URI. + * Return a principal with the specified certificate fingerprint, subject + * name (the full name or concatenated set of names of the entity + * represented by the certificate), pretty name, certificate, and + * codebase URI. The certificate fingerprint and subject name MUST be + * nonempty; otherwise an error will be thrown. Similarly, aCert must + * not be null. */ - [noscript] nsIPrincipal getCertificatePrincipal(in string CertID, in nsIURI aURI); + [noscript] nsIPrincipal + getCertificatePrincipal(in AUTF8String aCertFingerprint, + in AUTF8String aSubjectName, + in AUTF8String aPrettyName, + in nsISupports aCert, + in nsIURI aURI); /** * Return a principal that has the same origin as aURI. @@ -209,7 +219,11 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager * Allow 'certificateID' to enable 'capability.' Can only be performed * by code signed by the system certificate. */ - void setCanEnableCapability(in string certificateID, in string capability, + // XXXbz Capabilities can't have non-ascii chars? + // XXXbz ideally we'd pass a subjectName here too, and the nsISupports + // cert we're enabling for... + void setCanEnableCapability(in AUTF8String certificateFingerprint, + in string capability, in short canEnable); /////////////////////// diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h index dafce92b782..eca11972262 100755 --- a/caps/include/nsPrincipal.h +++ b/caps/include/nsPrincipal.h @@ -68,14 +68,28 @@ public: // Either Init() or InitFromPersistent() must be called before // the principal is in a usable state. - nsresult Init(const char *aCertID, nsIURI *aCodebase); + nsresult Init(const nsACString& aCertFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert, + nsIURI *aCodebase); nsresult InitFromPersistent(const char* aPrefName, - const char* aToken, + const nsCString& aFingerprint, + const nsCString& aSubjectName, + const nsACString& aPrettyName, const char* aGrantedList, const char* aDeniedList, + nsISupports* aCert, PRBool aIsCert, PRBool aTrusted); + // Call this to ensure that this principal has a subject name, a pretty name, + // and a cert pointer. This method will throw if there is already a + // different subject name or if this principal has no certificate. + nsresult EnsureCertData(const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert); + enum AnnotationValue { AnnotationEnabled=1, AnnotationDisabled }; void SetURI(nsIURI *aURI); @@ -96,16 +110,24 @@ protected: // that we can use yet. struct Certificate { - Certificate(const char* aCertID, const char* aName) - : certificateID(aCertID), - commonName(aName) + Certificate(const nsACString& aFingerprint, const nsACString& aSubjectName, + const nsACString& aPrettyName, nsISupports* aCert) + : fingerprint(aFingerprint), + subjectName(aSubjectName), + prettyName(aPrettyName), + cert(aCert) { }; - nsCString certificateID; - nsCString commonName; + nsCString fingerprint; + nsCString subjectName; + nsCString prettyName; + nsCOMPtr cert; }; - nsresult SetCertificate(const char* aCertID, const char* aName); + nsresult SetCertificate(const nsACString& aFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert); // Keep this is a pointer, even though it may slightly increase the // cost of keeping a certificate, this is a good tradeoff though since diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index b32503df2b0..01069d6f997 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -429,6 +429,18 @@ private: nsresult CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal** result); + // This is just like the API method, but it doesn't check that the subject + // name is nonempty or aCertificate is non-null, and it doesn't change the + // certificate in the table (if any) in any way if aModifyTable is false. + nsresult + DoGetCertificatePrincipal(const nsACString& aCertFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCertificate, + nsIURI* aURI, + PRBool aModifyTable, + nsIPrincipal **result); + // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script for the // context. Callers MUST pass in a non-null rv here. @@ -486,7 +498,10 @@ private: InitPrefs(); static nsresult - PrincipalPrefNames(const char* pref, char** grantedPref, char** deniedPref); + GetPrincipalPrefNames(const char* prefBase, + nsCString& grantedPref, + nsCString& deniedPref, + nsCString& subjectNamePref); nsresult InitPolicies(); diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index 063982f805c..97a399278ce 100755 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -100,20 +100,24 @@ nsPrincipal::nsPrincipal() } nsresult -nsPrincipal::Init(const char *aCertID, nsIURI *aCodebase) +nsPrincipal::Init(const nsACString& aCertFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert, + nsIURI *aCodebase) { NS_ENSURE_STATE(!mInitialized); - NS_ENSURE_ARG_POINTER(aCertID || aCodebase); // better have one of these. + NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() || aCodebase); // better have one of these. mInitialized = PR_TRUE; mCodebase = aCodebase; nsresult rv; - if (aCertID) { - rv = SetCertificate(aCertID, nsnull); + if (!aCertFingerprint.IsEmpty()) { + rv = SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert); if (NS_SUCCEEDED(rv)) { - rv = mJSPrincipals.Init(this, aCertID); + rv = mJSPrincipals.Init(this, mCert->fingerprint.get()); } } else { @@ -238,9 +242,19 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult) return NS_OK; } - nsXPIDLCString otherCertID; - aOther->GetCertificateID(getter_Copies(otherCertID)); - *aResult = otherCertID.Equals(mCert->certificateID); + nsCAutoString str; + aOther->GetFingerprint(str); + *aResult = str.Equals(mCert->fingerprint); + + // If either subject name is empty, just let the result stand (so that + // nsScriptSecurityManager::SetCanEnableCapability works), but if they're + // both nonempty, only claim equality if they're equal. + if (*aResult && !mCert->subjectName.IsEmpty()) { + // Check the other principal's subject name + aOther->GetSubjectName(str); + *aResult = str.Equals(mCert->subjectName) || str.IsEmpty(); + } + return NS_OK; } @@ -489,15 +503,18 @@ nsPrincipal::SetURI(nsIURI* aURI) nsresult -nsPrincipal::SetCertificate(const char* aID, const char* aName) +nsPrincipal::SetCertificate(const nsACString& aFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert) { NS_ENSURE_STATE(!mCert); - if (!aID && !aName) { - return NS_ERROR_INVALID_POINTER; + if (aFingerprint.IsEmpty()) { + return NS_ERROR_INVALID_ARG; } - mCert = new Certificate(aID, aName); + mCert = new Certificate(aFingerprint, aSubjectName, aPrettyName, aCert); if (!mCert) { return NS_ERROR_OUT_OF_MEMORY; } @@ -506,44 +523,46 @@ nsPrincipal::SetCertificate(const char* aID, const char* aName) } NS_IMETHODIMP -nsPrincipal::GetCertificateID(char** aID) +nsPrincipal::GetFingerprint(nsACString& aFingerprint) { NS_ENSURE_STATE(mCert); - *aID = ToNewCString(mCert->certificateID); - if (!*aID) { - return NS_ERROR_OUT_OF_MEMORY; - } + aFingerprint = mCert->fingerprint; return NS_OK; } NS_IMETHODIMP -nsPrincipal::GetCommonName(char** aName) +nsPrincipal::GetPrettyName(nsACString& aName) { NS_ENSURE_STATE(mCert); - *aName = ToNewCString(mCert->commonName); - if (!*aName) { - return NS_ERROR_OUT_OF_MEMORY; - } + aName = mCert->prettyName; return NS_OK; } NS_IMETHODIMP -nsPrincipal::SetCommonName(const char* aName) +nsPrincipal::GetSubjectName(nsACString& aName) { - if (!mCert) { - NS_ERROR("You must first initialize the certificate with an ID"); - return NS_ERROR_FAILURE; - } + NS_ENSURE_STATE(mCert); - mCert->commonName = aName; + aName = mCert->subjectName; return NS_OK; } +NS_IMETHODIMP +nsPrincipal::GetCertificate(nsISupports** aCertificate) +{ + if (mCert) { + NS_IF_ADDREF(*aCertificate = mCert->cert); + } + else { + *aCertificate = nsnull; + } + return NS_OK; +} NS_IMETHODIMP nsPrincipal::GetHashValue(PRUint32* aValue) @@ -552,7 +571,7 @@ nsPrincipal::GetHashValue(PRUint32* aValue) // If there is a certificate, it takes precendence over the codebase. if (mCert) { - *aValue = nsCRT::HashCode(mCert->certificateID.get(), nsnull); + *aValue = nsCRT::HashCode(mCert->fingerprint.get(), nsnull); } else { nsCAutoString str; @@ -583,9 +602,12 @@ nsPrincipal::SetDomain(nsIURI* aDomain) nsresult nsPrincipal::InitFromPersistent(const char* aPrefName, - const char* aToken, + const nsCString& aToken, + const nsCString& aSubjectName, + const nsACString& aPrettyName, const char* aGrantedList, const char* aDeniedList, + nsISupports* aCert, PRBool aIsCert, PRBool aTrusted) { @@ -599,7 +621,8 @@ nsPrincipal::InitFromPersistent(const char* aPrefName, nsresult rv; if (aIsCert) { - rv = SetCertificate(aToken, nsnull); + rv = SetCertificate(aToken, aSubjectName, aPrettyName, aCert); + if (NS_FAILED(rv)) { return rv; } @@ -614,7 +637,7 @@ nsPrincipal::InitFromPersistent(const char* aPrefName, mTrusted = aTrusted; } - rv = mJSPrincipals.Init(this, aToken); + rv = mJSPrincipals.Init(this, aToken.get()); NS_ENSURE_SUCCESS(rv, rv); //-- Save the preference name @@ -641,6 +664,24 @@ nsPrincipal::InitFromPersistent(const char* aPrefName, return rv; } +nsresult +nsPrincipal::EnsureCertData(const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCert) +{ + NS_ENSURE_STATE(mCert); + + if (!mCert->subjectName.IsEmpty() && + !mCert->subjectName.Equals(aSubjectName)) { + return NS_ERROR_INVALID_ARG; + } + + mCert->subjectName = aSubjectName; + mCert->prettyName = aPrettyName; + mCert->cert = aCert; + return NS_OK; +} + struct CapabilityList { nsCString* granted; @@ -667,6 +708,7 @@ AppendCapability(nsHashKey *aKey, void *aData, void *capListPtr) NS_IMETHODIMP nsPrincipal::GetPreferences(char** aPrefName, char** aID, + char** aSubjectName, char** aGrantedList, char** aDeniedList) { if (mPrefName.IsEmpty()) { @@ -683,11 +725,13 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, *aPrefName = nsnull; *aID = nsnull; + *aSubjectName = nsnull; *aGrantedList = nsnull; *aDeniedList = nsnull; char *prefName = nsnull; char *id = nsnull; + char *subjectName = nsnull; char *granted = nsnull; char *denied = nsnull; @@ -698,9 +742,12 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, } //-- ID - nsresult rv; + nsresult rv = NS_OK; if (mCert) { - rv = GetCertificateID(&id); + id = ToNewCString(mCert->fingerprint); + if (!id) { + rv = NS_ERROR_OUT_OF_MEMORY; + } } else { rv = GetOrigin(&id); @@ -711,6 +758,18 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, return rv; } + if (mCert) { + subjectName = ToNewCString(mCert->subjectName); + } else { + subjectName = ToNewCString(EmptyCString()); + } + + if (!subjectName) { + nsMemory::Free(prefName); + nsMemory::Free(id); + return NS_ERROR_OUT_OF_MEMORY; + } + //-- Capabilities nsCAutoString grantedListStr, deniedListStr; CapabilityList capList = CapabilityList(); @@ -724,6 +783,7 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, if (!granted) { nsMemory::Free(prefName); nsMemory::Free(id); + nsMemory::Free(subjectName); return NS_ERROR_OUT_OF_MEMORY; } } @@ -734,6 +794,7 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, if (!denied) { nsMemory::Free(prefName); nsMemory::Free(id); + nsMemory::Free(subjectName); if (granted) { nsMemory::Free(granted); } @@ -743,6 +804,7 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID, *aPrefName = prefName; *aID = id; + *aSubjectName = subjectName; *aGrantedList = granted; *aDeniedList = denied; diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index e694cb75915..ad3af1839e3 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -1687,10 +1687,35 @@ nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem) } NS_IMETHODIMP -nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID, +nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCertificate, nsIURI* aURI, nsIPrincipal **result) { + *result = nsnull; + + NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() && + !aSubjectName.IsEmpty() && + aCertificate); + + return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName, + aPrettyName, aCertificate, aURI, PR_TRUE, + result); +} + +nsresult +nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint, + const nsACString& aSubjectName, + const nsACString& aPrettyName, + nsISupports* aCertificate, + nsIURI* aURI, + PRBool aModifyTable, + nsIPrincipal **result) +{ + NS_ENSURE_ARG(!aCertFingerprint.IsEmpty()); + // Create a certificate principal out of the certificate ID // and URI given to us. We will use this principal to test // equality when doing our hashtable lookups below. @@ -1698,7 +1723,8 @@ nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID, if (!certificate) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = certificate->Init(aCertID, aURI); + nsresult rv = certificate->Init(aCertFingerprint, aSubjectName, + aPrettyName, aCertificate, aURI); NS_ENSURE_SUCCESS(rv, rv); // Check to see if we already have this principal. @@ -1706,7 +1732,24 @@ nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID, mPrincipals.Get(certificate, getter_AddRefs(fromTable)); if (fromTable) { // Bingo. We found the certificate in the table, which means - // that it has escalated priveleges. + // that it has escalated privileges. + + if (aModifyTable) { + // Make sure this principal has names, so if we ever go to save it + // we'll save them. If we get a name mismatch here we'll throw, + // but that's desirable. + rv = NS_STATIC_CAST(nsPrincipal*, + NS_STATIC_CAST(nsIPrincipal*, fromTable)) + ->EnsureCertData(aSubjectName, aPrettyName, aCertificate); + if (NS_FAILED(rv)) { + // We have a subject name mismatch for the same cert id. + // Hand back the |certificate| object we created and don't give + // it any rights from the table. + NS_ADDREF(*result = certificate); + return NS_OK; + } + } + if (!aURI) { // We were asked to just get the base certificate, so output // what we have in the table. @@ -1720,19 +1763,24 @@ nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID, // things. nsXPIDLCString prefName; nsXPIDLCString id; + nsXPIDLCString subjectName; nsXPIDLCString granted; nsXPIDLCString denied; rv = fromTable->GetPreferences(getter_Copies(prefName), getter_Copies(id), + getter_Copies(subjectName), getter_Copies(granted), getter_Copies(denied)); + // XXXbz assert something about subjectName and aSubjectName here? if (NS_SUCCEEDED(rv)) { certificate = new nsPrincipal(); if (!certificate) return NS_ERROR_OUT_OF_MEMORY; rv = certificate->InitFromPersistent(prefName, id, + subjectName, aPrettyName, granted, denied, + aCertificate, PR_TRUE, PR_FALSE); if (NS_SUCCEEDED(rv)) certificate->SetURI(aURI); @@ -1752,7 +1800,8 @@ nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **re if (!codebase) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = codebase->Init(nsnull, aURI); + nsresult rv = codebase->Init(EmptyCString(), EmptyCString(), + EmptyCString(), nsnull, aURI); if (NS_FAILED(rv)) return rv; @@ -2060,36 +2109,45 @@ nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave) //-- Save to prefs nsXPIDLCString idPrefName; nsXPIDLCString id; + nsXPIDLCString subjectName; nsXPIDLCString grantedList; nsXPIDLCString deniedList; nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName), getter_Copies(id), + getter_Copies(subjectName), getter_Copies(grantedList), getter_Copies(deniedList)); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - nsXPIDLCString grantedPrefName; - nsXPIDLCString deniedPrefName; - rv = PrincipalPrefNames( idPrefName, - getter_Copies(grantedPrefName), - getter_Copies(deniedPrefName) ); + nsCAutoString grantedPrefName; + nsCAutoString deniedPrefName; + nsCAutoString subjectNamePrefName; + rv = GetPrincipalPrefNames( idPrefName, + grantedPrefName, + deniedPrefName, + subjectNamePrefName ); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; mIsWritingPrefs = PR_TRUE; if (grantedList) - mSecurityPref->SecuritySetCharPref(grantedPrefName, grantedList); + mSecurityPref->SecuritySetCharPref(grantedPrefName.get(), grantedList); else - mSecurityPref->SecurityClearUserPref(grantedPrefName); + mSecurityPref->SecurityClearUserPref(grantedPrefName.get()); if (deniedList) - mSecurityPref->SecuritySetCharPref(deniedPrefName, deniedList); + mSecurityPref->SecuritySetCharPref(deniedPrefName.get(), deniedList); else - mSecurityPref->SecurityClearUserPref(deniedPrefName); + mSecurityPref->SecurityClearUserPref(deniedPrefName.get()); - if (grantedList || deniedList) + if (grantedList || deniedList) { mSecurityPref->SecuritySetCharPref(idPrefName, id); - else + mSecurityPref->SecuritySetCharPref(subjectNamePrefName.get(), + subjectName); + } + else { mSecurityPref->SecurityClearUserPref(idPrefName); + mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get()); + } mIsWritingPrefs = PR_FALSE; @@ -2265,14 +2323,14 @@ nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrinci PRBool hasCert; aPrincipal->GetHasCertificate(&hasCert); if (hasCert) - rv = aPrincipal->GetCommonName(getter_Copies(val)); + rv = aPrincipal->GetPrettyName(val); else rv = aPrincipal->GetOrigin(getter_Copies(val)); if (NS_FAILED(rv)) return PR_FALSE; - NS_ConvertUTF8toUTF16 location(val.get()); + NS_ConvertUTF8toUTF16 location(val); NS_ConvertASCIItoUTF16 capability(aCapability); FormatCapabilityString(capability); const PRUnichar *formatStrings[] = { location.get(), capability.get() }; @@ -2387,14 +2445,14 @@ nsScriptSecurityManager::EnableCapability(const char *capability) nsresult rv; principal->GetHasCertificate(&hasCert); if (hasCert) - rv = principal->GetCommonName(getter_Copies(val)); + rv = principal->GetPrettyName(val); else rv = principal->GetOrigin(getter_Copies(val)); if (NS_FAILED(rv)) return rv; - NS_ConvertUTF8toUTF16 location(val.get()); + NS_ConvertUTF8toUTF16 location(val); NS_ConvertUTF8toUTF16 cap(capability); const PRUnichar *formatStrings[] = { location.get(), cap.get() }; @@ -2452,10 +2510,12 @@ nsScriptSecurityManager::DisableCapability(const char *capability) //////////////// Master Certificate Functions /////////////////////////////////////// NS_IMETHODIMP -nsScriptSecurityManager::SetCanEnableCapability(const char* certificateID, +nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint, const char* capability, PRInt16 canEnable) { + NS_ENSURE_ARG(!certFingerprint.IsEmpty()); + nsresult rv; nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv); if (NS_FAILED(rv)) @@ -2511,7 +2571,10 @@ nsScriptSecurityManager::SetCanEnableCapability(const char* certificateID, //-- Get the target principal nsCOMPtr objectPrincipal; - rv = GetCertificatePrincipal(certificateID, nsnull, getter_AddRefs(objectPrincipal)); + rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(), + EmptyCString(), nsnull, + nsnull, PR_FALSE, + getter_AddRefs(objectPrincipal)); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = objectPrincipal->SetCanEnableCapability(capability, canEnable); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; @@ -3261,33 +3324,44 @@ nsScriptSecurityManager::InitDomainPolicy(JSContext* cx, } +// XXXbz We should really just get a prefbranch to handle this... nsresult -nsScriptSecurityManager::PrincipalPrefNames(const char* pref, - char** grantedPref, char** deniedPref) +nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase, + nsCString& grantedPref, + nsCString& deniedPref, + nsCString& subjectNamePref) { - char* lastDot = PL_strrchr(pref, '.'); + char* lastDot = PL_strrchr(prefBase, '.'); if (!lastDot) return NS_ERROR_FAILURE; - PRInt32 prefLen = lastDot - pref + 1; + PRInt32 prefLen = lastDot - prefBase + 1; - *grantedPref = nsnull; - *deniedPref = nsnull; + grantedPref.Assign(prefBase, prefLen); + deniedPref.Assign(prefBase, prefLen); + subjectNamePref.Assign(prefBase, prefLen); - static const char granted[] = "granted"; - *grantedPref = (char*)PR_MALLOC(prefLen + sizeof(granted)); - if (!grantedPref) return NS_ERROR_OUT_OF_MEMORY; - PL_strncpy(*grantedPref, pref, prefLen); - PL_strcpy(*grantedPref + prefLen, granted); +#define GRANTED "granted" +#define DENIED "denied" +#define SUBJECTNAME "subjectName" - static const char denied[] = "denied"; - *deniedPref = (char*)PR_MALLOC(prefLen + sizeof(denied)); - if (!deniedPref) - { - PR_FREEIF(*grantedPref); + grantedPref.AppendLiteral(GRANTED); + if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) { return NS_ERROR_OUT_OF_MEMORY; } - PL_strncpy(*deniedPref, pref, prefLen); - PL_strcpy(*deniedPref + prefLen, denied); + deniedPref.AppendLiteral(DENIED); + if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) { + return NS_ERROR_OUT_OF_MEMORY; + } + + subjectNamePref.AppendLiteral(SUBJECTNAME); + if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) { + return NS_ERROR_OUT_OF_MEMORY; + } + +#undef SUBJECTNAME +#undef DENIED +#undef GRANTED + return NS_OK; } @@ -3311,7 +3385,8 @@ nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefN static const char idSuffix[] = ".id"; for (PRUint32 c = 0; c < aPrefCount; c++) { - PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) - (sizeof(idSuffix)-1); + PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) - + (NS_ARRAY_LENGTH(idSuffix) - 1); if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0) continue; @@ -3319,27 +3394,35 @@ nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefN if (NS_FAILED(mSecurityPref->SecurityGetCharPref(aPrefNames[c], getter_Copies(id)))) return NS_ERROR_FAILURE; - nsXPIDLCString grantedPrefName; - nsXPIDLCString deniedPrefName; - nsresult rv = PrincipalPrefNames(aPrefNames[c], - getter_Copies(grantedPrefName), - getter_Copies(deniedPrefName)); + nsCAutoString grantedPrefName; + nsCAutoString deniedPrefName; + nsCAutoString subjectNamePrefName; + nsresult rv = GetPrincipalPrefNames(aPrefNames[c], + grantedPrefName, + deniedPrefName, + subjectNamePrefName); if (rv == NS_ERROR_OUT_OF_MEMORY) return rv; if (NS_FAILED(rv)) continue; nsXPIDLCString grantedList; - mSecurityPref->SecurityGetCharPref(grantedPrefName, getter_Copies(grantedList)); + mSecurityPref->SecurityGetCharPref(grantedPrefName.get(), + getter_Copies(grantedList)); nsXPIDLCString deniedList; - mSecurityPref->SecurityGetCharPref(deniedPrefName, getter_Copies(deniedList)); + mSecurityPref->SecurityGetCharPref(deniedPrefName.get(), + getter_Copies(deniedList)); + nsXPIDLCString subjectName; + mSecurityPref->SecurityGetCharPref(subjectNamePrefName.get(), + getter_Copies(subjectName)); //-- Delete prefs if their value is the empty string if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty())) { mSecurityPref->SecurityClearUserPref(aPrefNames[c]); - mSecurityPref->SecurityClearUserPref(grantedPrefName); - mSecurityPref->SecurityClearUserPref(deniedPrefName); + mSecurityPref->SecurityClearUserPref(grantedPrefName.get()); + mSecurityPref->SecurityClearUserPref(deniedPrefName.get()); + mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get()); continue; } @@ -3371,8 +3454,9 @@ nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefN if (!newPrincipal) return NS_ERROR_OUT_OF_MEMORY; - rv = newPrincipal->InitFromPersistent(aPrefNames[c], id.get(), - grantedList, deniedList, + rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName, + EmptyCString(), + grantedList, deniedList, nsnull, isCert, isTrusted); if (NS_SUCCEEDED(rv)) mPrincipals.Put(newPrincipal, newPrincipal); diff --git a/caps/src/nsSecurityManagerFactory.cpp b/caps/src/nsSecurityManagerFactory.cpp index a9e1bfd6151..67fff2c4247 100644 --- a/caps/src/nsSecurityManagerFactory.cpp +++ b/caps/src/nsSecurityManagerFactory.cpp @@ -51,6 +51,7 @@ #include "nsXPIDLString.h" #include "nsCOMPtr.h" #include "nsIServiceManager.h" +#include "nsString.h" #include "nsPrefsCID.h" /////////////////////// @@ -102,6 +103,30 @@ getStringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsv return JS_GetStringBytes(str); } +static void +getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, + uintN argc, jsval *argv, nsCString& aRetval) +{ + if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) { + JS_ReportError(cx, "String argument expected"); + aRetval.Truncate(); + return; + } + + /* + * We don't want to use JS_ValueToString because we want to be able + * to have an object to represent a target in subsequent versions. + */ + JSString *str = JSVAL_TO_STRING(argv[argNum]); + if (!str) { + aRetval.Truncate(); + return; + } + + PRUnichar *data = (PRUnichar*)JS_GetStringChars(str); + CopyUTF16toUTF8(data, aRetval); +} + PR_STATIC_CALLBACK(JSBool) netscape_security_isPrivilegeEnabled(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -196,9 +221,10 @@ netscape_security_setCanEnablePrivilege(JSContext *cx, JSObject *obj, uintN argc jsval *argv, jsval *rval) { if (argc < 2) return JS_FALSE; - char *principalID = getStringArgument(cx, obj, 0, argc, argv); + nsCAutoString principalFingerprint; + getUTF8StringArgument(cx, obj, 0, argc, argv, principalFingerprint); char *cap = getStringArgument(cx, obj, 1, argc, argv); - if (!principalID || !cap) + if (principalFingerprint.IsEmpty() || !cap) return JS_FALSE; nsresult rv; @@ -209,7 +235,7 @@ netscape_security_setCanEnablePrivilege(JSContext *cx, JSObject *obj, uintN argc // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - rv = securityManager->SetCanEnableCapability(principalID, cap, + rv = securityManager->SetCanEnableCapability(principalFingerprint, cap, nsIPrincipal::ENABLE_GRANTED); if (NS_FAILED(rv)) return JS_FALSE; @@ -220,8 +246,9 @@ PR_STATIC_CALLBACK(JSBool) netscape_security_invalidate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - char *principalID = getStringArgument(cx, obj, 0, argc, argv); - if (!principalID) + nsCAutoString principalFingerprint; + getUTF8StringArgument(cx, obj, 0, argc, argv, principalFingerprint); + if (principalFingerprint.IsEmpty()) return JS_FALSE; nsresult rv; @@ -232,7 +259,7 @@ netscape_security_invalidate(JSContext *cx, JSObject *obj, uintN argc, // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - rv = securityManager->SetCanEnableCapability(principalID, + rv = securityManager->SetCanEnableCapability(principalFingerprint, nsPrincipal::sInvalid, nsIPrincipal::ENABLE_GRANTED); if (NS_FAILED(rv)) diff --git a/caps/src/nsSystemPrincipal.cpp b/caps/src/nsSystemPrincipal.cpp index 163a843f492..c32622c4f54 100644 --- a/caps/src/nsSystemPrincipal.cpp +++ b/caps/src/nsSystemPrincipal.cpp @@ -84,12 +84,14 @@ nsSystemPrincipal::Release() /////////////////////////////////////// NS_IMETHODIMP -nsSystemPrincipal::GetPreferences(char** aPrefName, char** aID, +nsSystemPrincipal::GetPreferences(char** aPrefName, char** aID, + char** aSubjectName, char** aGrantedList, char** aDeniedList) { // The system principal should never be streamed out *aPrefName = nsnull; *aID = nsnull; + *aSubjectName = nsnull; *aGrantedList = nsnull; *aDeniedList = nsnull; @@ -181,22 +183,27 @@ nsSystemPrincipal::GetOrigin(char** aOrigin) } NS_IMETHODIMP -nsSystemPrincipal::GetCertificateID(char** aID) +nsSystemPrincipal::GetFingerprint(nsACString& aID) { - *aID = nsnull; - return NS_OK; + return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP -nsSystemPrincipal::GetCommonName(char** aName) +nsSystemPrincipal::GetPrettyName(nsACString& aName) { - *aName = nsnull; - return NS_OK; + return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP -nsSystemPrincipal::SetCommonName(const char* aName) +nsSystemPrincipal::GetSubjectName(nsACString& aName) { + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsSystemPrincipal::GetCertificate(nsISupports** aCertificate) +{ + *aCertificate = nsnull; return NS_OK; } diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 2148027b5bf..4132aac6ba7 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -455,25 +455,32 @@ nsJARChannel::GetOwner(nsISupports **result) if (NS_FAILED(rv)) return rv; if (cert) { - nsXPIDLCString certID; - rv = cert->GetCertificateID(getter_Copies(certID)); + nsCAutoString certFingerprint; + rv = cert->GetFingerprint(certFingerprint); if (NS_FAILED(rv)) return rv; - nsXPIDLCString commonName; - rv = cert->GetCommonName(getter_Copies(commonName)); + nsCAutoString subjectName; + rv = cert->GetSubjectName(subjectName); if (NS_FAILED(rv)) return rv; + nsCAutoString prettyName; + rv = cert->GetPrettyName(prettyName); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr certificate; + rv = cert->GetCertificate(getter_AddRefs(certificate)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; - rv = secMan->GetCertificatePrincipal(certID, mJarBaseURI, + rv = secMan->GetCertificatePrincipal(certFingerprint, subjectName, + prettyName, certificate, + mJarBaseURI, getter_AddRefs(cert)); if (NS_FAILED(rv)) return rv; - rv = cert->SetCommonName(commonName); - if (NS_FAILED(rv)) return rv; - mOwner = do_QueryInterface(cert, &rv); if (NS_FAILED(rv)) return rv; diff --git a/modules/oji/src/nsCSecurityContext.cpp b/modules/oji/src/nsCSecurityContext.cpp index 9d5546bdac9..3856f1f9898 100644 --- a/modules/oji/src/nsCSecurityContext.cpp +++ b/modules/oji/src/nsCSecurityContext.cpp @@ -156,8 +156,8 @@ nsCSecurityContext::GetCertificateID(char* buf, int buflen) return NS_ERROR_FAILURE; } - nsXPIDLCString certificate; - principal->GetCertificateID(getter_Copies(certificate)); + nsCAutoString certificate; + principal->GetFingerprint(certificate); PRInt32 certlen = certificate.Length(); if (buflen <= certlen) { diff --git a/modules/oji/src/nsJVMManager.cpp b/modules/oji/src/nsJVMManager.cpp index c6e28bc196c..bfcbfa00c53 100644 --- a/modules/oji/src/nsJVMManager.cpp +++ b/modules/oji/src/nsJVMManager.cpp @@ -903,7 +903,10 @@ nsJVMManager::IsLiveConnectEnabled(void) * be derived, should have been verified before this method is * called. */ - +// XXXbz this function has been deprecated for 4.5 years. We have no +// callers in the tree. Is it time to remove it? It's returning +// PRBools for a NS_METHOD, and NS_METHOD for an interface method, for +// goodness' sake! NS_METHOD nsJVMManager::IsAllPermissionGranted( const char * lastFP, @@ -912,6 +915,10 @@ nsJVMManager::IsAllPermissionGranted( const char * rootCN, PRBool * isGranted) { + if (!lastFP || !lastCN) { + return PR_FALSE; + } + nsresult rv = NS_OK; nsCOMPtr pIPrincipal; @@ -926,13 +933,16 @@ nsJVMManager::IsAllPermissionGranted( // The fingerprint is a one way hash of this certificate. It is used // as the key to store the principal in the principal database. - rv = secMan->GetCertificatePrincipal(lastFP, nsnull, + // XXXbz using the |lastCN| for the subjectName for lack of + // anything better. Also not passing in a pointer to a cert, + // since we don't have one. + rv = secMan->GetCertificatePrincipal(nsDependentCString(lastFP), + nsDependentCString(lastCN), + nsDependentCString(lastCN), + nsnull, nsnull, getter_AddRefs(pIPrincipal)); if (NS_FAILED(rv)) return PR_FALSE; - // Set the common name. - rv = pIPrincipal->SetCommonName(lastCN); - PRInt16 ret; secMan->RequestCapability(pIPrincipal,"AllPermission",&ret); diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index d448b49dae8..5f8fd7f3111 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -1705,25 +1705,28 @@ nsNSSComponent::VerifySignature(const char* aRSABuf, PRUint32 aRSABufLen, if (NS_FAILED(rv2)) { break; } - nsCOMPtr certPrincipal; - rv2 = mScriptSecurityManager-> - GetCertificatePrincipal(NS_ConvertUTF16toUTF8(fingerprint).get(), - nsnull, getter_AddRefs(certPrincipal)); - if (NS_FAILED(rv2) || !certPrincipal) { - break; - } - nsAutoString orgName; rv2 = pCert->GetOrganization(orgName); if (NS_FAILED(rv2)) { break; } - rv2 = certPrincipal->SetCommonName(NS_ConvertUTF16toUTF8(orgName).get()); + nsAutoString subjectName; + rv2 = pCert->GetSubjectName(subjectName); if (NS_FAILED(rv2)) { break; } - NS_ADDREF(*aPrincipal = certPrincipal); + nsCOMPtr certPrincipal; + rv2 = mScriptSecurityManager-> + GetCertificatePrincipal(NS_ConvertUTF16toUTF8(fingerprint), + NS_ConvertUTF16toUTF8(subjectName), + NS_ConvertUTF16toUTF8(orgName), + pCert, nsnull, getter_AddRefs(certPrincipal)); + if (NS_FAILED(rv2) || !certPrincipal) { + break; + } + + certPrincipal.swap(*aPrincipal); } while (0); } diff --git a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in index 06c6e624fa6..a9097fdc37e 100644 --- a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in +++ b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in @@ -2646,12 +2646,14 @@ ExtensionManager.prototype = { var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"] .createInstance(Components.interfaces.nsIZipReader); zipReader.init(entry); - var commonName = ""; + var prettyName = ""; try { var jar = zipReader.QueryInterface(Components.interfaces.nsIJAR); var principal = { }; var certPrincipal = zipReader.getCertificatePrincipal(null, principal); - commonName = principal.value.commonName; + // XXXbz This string could be empty. This needs better + // UI to present principal.value.certificate's subject. + prettyName = principal.value.prettyName; } catch (e) { } xpinstallStrings = xpinstallStrings.concat([item.name, diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index 31cf1cc1a34..2e1c2696780 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -142,9 +142,12 @@ nsXPITriggerItem::SetPrincipal(nsIPrincipal* aPrincipal) PRBool hasCert; aPrincipal->GetHasCertificate(&hasCert); if (hasCert) { - nsXPIDLCString cName; - aPrincipal->GetCommonName(getter_Copies(cName)); - CopyUTF8toUTF16(cName, mCertName); + nsCAutoString prettyName; + // XXXbz should this really be using the prettyName? Perhaps + // it wants to get the subjectName or nsIX509Cert and display + // it sanely? + aPrincipal->GetPrettyName(prettyName); + CopyUTF8toUTF16(prettyName, mCertName); } }